diff --git a/004ec9e5.9091d5cc.js b/004ec9e5.7aaf2b9f.js similarity index 97% rename from 004ec9e5.9091d5cc.js rename to 004ec9e5.7aaf2b9f.js index 49f81aa2b4..f04ca90663 100644 --- a/004ec9e5.9091d5cc.js +++ b/004ec9e5.7aaf2b9f.js @@ -1,2 +1,2 @@ -/*! For license information please see 004ec9e5.9091d5cc.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{153:function(n,t,e){"use strict";e.r(t);e(452);var r=e(0),u=e.n(r),i=e(471),a=e(540),o=e(454);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})))}},447: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")},471:function(n,t,e){"use strict";e(481);var r=e(0),u=e.n(r),i=e(482),a=e(470),o=e(1),c=(e(472),e(473),e(483),e(454)),l=e(484),f=e(466),s=e.n(f),v=e(485),h=e.n(v),d=e(460),p=e(447),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(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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),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(z,{alt:f.alt,url:v})):u.a.createElement(z,{alt:f.alt,url:v})),u.a.createElement("small",null,a),u.a.createElement("br",null))))},W=e(486),M=e(487),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,D=n.keywords,g=(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}),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)))}},474:function(n,t,e){"use strict";var r=e(9),u=e(0),i=e.n(u),a=e(447),o=e.n(a),c=e(460),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)}}},475: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]",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*$/,V=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,G=/[\\^$.*+?()[\]{}|]/g,Z=RegExp(G.source),H=/^\s+|\s+$/g,K=/^\s+/,J=/\s+$/,Q=/\{(?:\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]",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,Vn=parseInt,Gn="object"==typeof n&&n&&n.Object===Object&&n,Zn="object"==typeof self&&self&&self.Object===Object&&self,Hn=Gn||Zn||Function("return this")(),Kn=t&&!t.nodeType&&t,Jn=Kn&&"object"==typeof r&&r&&!r.nodeType&&r,Qn=Jn&&Jn.exports===Kn,Yn=Qn&&Gn.process,Xn=function(){try{var n=Jn&&Jn.require&&Jn.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 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 Kt=function n(t){var e,r=(t=null==t?Hn:Kt.defaults(Hn.Object(),t,Kt.pick(Hn,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=Hn._,Nn=gn("^"+Fn.call(Cn).replace(G,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Bn=Qn?t.Buffer:void 0,Ln=t.Symbol,zn=t.Uint8Array,$n=Bn?Bn.allocUnsafe:void 0,Gn=Pt(Dn.getPrototypeOf,Dn),Zn=Dn.create,Kn=En.propertyIsEnumerable,Jn=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){}}(),Jt=t.clearTimeout!==Hn.clearTimeout&&t.clearTimeout,Qt=u&&u.now!==Hn.Date.now&&u.now,Yt=t.setTimeout!==Hn.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),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"),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($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 Je(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 gu(n,a)}else{var I=ei(n),S=I==h||I==d;if(Ra(n))return su(n,o);if(I==g||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 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,o)}}i||(i=new ze);var L=i.get(n);if(L)return L;i.set(n,a),Ha(n)?n.forEach((function(r){a.add(Je(r,t,e,r,n,i))})):qa(n)&&n.forEach((function(r,u){a.set(u,Je(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,Je(r,t,e,u,n,i))})),a}function Qe(n,t,e){var r=e.length;if(null==n)return!r;for(n=Dn(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=Qu(this,n).delete(n);return this.size-=t?1:0,t},Le.prototype.get=function(n){return Qu(this,n).get(n)},Le.prototype.has=function(n){return Qu(this,n).has(n)},Le.prototype.set=function(n,t){var e=Qu(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(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 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,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&&Jn.call(o,c,1),Jn.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)?Jn.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,Go),n+"")}function Wr(n){return We(jo(n))}function Mr(n,t){var e=jo(n);return wi(e,Ke(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&&!Ja(a)&&(e?a<=t:a=200){var l=t?null:zu(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=Jt||function(n){return Hn.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=Ja(n),a=void 0!==t,o=null===t,c=t==t,l=Ja(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=Dn(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"==Hu(a))var o=new Ne([],!0)}for(r=o?r:e;++r1&&m.reverse(),s&&l<_&&(m.length=l),this&&this!==Hn&&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=Qr(e),r=Qr(r)):(e=Jr(e),r=Jr(r)),u=n(e,r)}return u}}function Nu(n){return qu((function(t){return t=dt(t,Nt(Ju())),Tr((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?" ":Qr(t)).length;if(e<2)return e?zr(t,n):t;var r=zr(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(Q,"{\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 He(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,Ju(t,3))}function oa(n,t){return(Ba(n)?lt:tr)(n,Ju(t,3))}var ca=mu((function(n,t,e){Cn.call(n,e)?n[e].push(t):Ze(n,e,[t])}));var la=Tr((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,Ju(t,3))}var va=mu((function(n,t,e){n[e?0:1].push(t)}),(function(){return[[],[]]}));var ha=Tr((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=Qt||function(){return Hn.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 Da(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 ga=Tr((function(n,t,e){var r=1;if(e.length){var u=$t(e,Ku(ga));r|=32}return Wu(n,r,t,e,u)})),_a=Tr((function(n,t,e){var r=3;if(e.length){var u=$t(e,Ku(_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(g,t),s?d(n):o}function D(n){var e=n-l;return void 0===l||e>=t||e<0||v&&n-f>=a}function g(){var n=da();if(D(n))return _(n);c=mi(g,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=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)),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=Tr((function(n,t){return Ye(n,1,t)})),ba=Tr((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(Ju())):dt(ir(t,1),Nt(Ju()))).length;return Tr((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")&&!Kn.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,za=tt?Nt(tt):function(n){return $a(n)&&hr(n)==s};function Ta(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)==D}function Ga(n){if(!$a(n)||hr(n)!=g)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 Ha=ut?Nt(ut):function(n){return $a(n)&&ei(n)==m};function Ka(n){return"string"==typeof n||!Ba(n)&&$a(n)&&hr(n)==y}function Ja(n){return"symbol"==typeof n||$a(n)&&hr(n)==b}var Qa=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 Ka(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: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?Ke(eo(n),0,4294967295):0}function uo(n){if("number"==typeof n)return n;if(Ja(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(H,"");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?"":Qr(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(He);var vo=Tr((function(n,t){n=Dn(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=Je(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 Do(n,e)}))}(n,t)}));function ko(n,t){if(null==n)return{};var e=dt(Gu(n),(function(n){return[n]}));return t=Ju(t),Ir(n,e,(function(n,e){return t(n,e[0])}))}var Ao=Tu(yo),xo=Tu(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,zt).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 zo=Fu((function(n,t,e){return n+(e?" ":"")+Wo(t)}));var To=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 Tn.test(n)}(n)?function(n){return n.match(Rn)||[]}(n):function(n){return n.match(nn)||[]}(n):n.match(t)||[]}var Uo=Tr((function(n,t){try{return at(n,void 0,t)}catch(e){return Ta(e)?e:new hn(e)}})),Po=qu((function(n,t){return ct(t,(function(t){t=Ci(t),Ze(n,t,ga(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:Je(n,1))}var Ho=Tr((function(n,t){return function(e){return _r(e,n,t)}})),Ko=Tr((function(n,t){return function(e){return _r(n,e,t)}}));function Jo(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__=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 Qo(){}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=Da,xe.bind=ga,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=Qr(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),Tr((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,Ju(t,3),!1,!0):[]},xe.takeWhile=function(n,t){return n&&n.length?tu(n,Ju(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):Ja(n)?[n]:gu(Fi(ao(n)))},xe.toPlainObject=io,xe.transform=function(n,t,e){var r=Ba(n),u=r||Ra(n)||Qa(n);if(t=Ju(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,Ju(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=Hi,xe.words=Mo,xe.wrap=function(n,t){return Ca(au(t),n)},xe.xor=Ki,xe.xorBy=Ji,xe.xorWith=Qi,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,Jo(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),Ke(uo(n),t,e)},xe.clone=function(n){return Je(n,4)},xe.cloneDeep=function(n){return Je(n,5)},xe.cloneDeepWith=function(n,t){return Je(n,5,t="function"==typeof t?t:void 0)},xe.cloneWith=function(n,t){return Je(n,4,t="function"==typeof t?t:void 0)},xe.conformsTo=function(n,t){return null==t||Qe(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=Qr(t);var r=n.length,u=e=void 0===e?r:Ke(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(z,Tt):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,Ju(t,3))},xe.find=ua,xe.findIndex=Ni,xe.findKey=function(n,t){return yt(n,Ju(t,3),cr)},xe.findLast=ia,xe.findLastIndex=Bi,xe.findLastKey=function(n,t){return yt(n,Ju(t,3),lr)},xe.floor=lc,xe.forEach=aa,xe.forEachRight=oa,xe.forIn=function(n,t){return null==n?n:ar(n,Ju(t,3),bo)},xe.forInRight=function(n,t){return null==n?n:or(n,Ju(t,3),bo)},xe.forOwn=function(n,t){return n&&cr(n,Ju(t,3))},xe.forOwnRight=function(n,t){return n&&lr(n,Ju(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=Do,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)),Ka(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=Ha,xe.isString=Ka,xe.isSymbol=Ja,xe.isTypedArray=Qa,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=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=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,Ju(t,2),dr):void 0},xe.mean=function(n){return Ct(n,Go)},xe.meanBy=function(n,t){return Ct(n,Ju(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,Ju(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 Hn._===this&&(Hn._=On),this},xe.noop=Qo,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)?Dt:xt,u=arguments.length<3;return r(n,Ju(t,4),e,u,nr)},xe.reduceRight=function(n,t,e){var r=Ba(n)?gt:xt,u=arguments.length<3;return r(n,Ju(t,4),e,u,tr)},xe.repeat=function(n,t,e){return t=(e?oi(n,t,e):void 0===t)?1:eo(t),zr(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=Ju(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=gn(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(Qr(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))&&T.test(n)?n.replace(R,Ht):n},xe.uniqueId=function(n){var t=++kn;return ao(n)+t},xe.upperCase=To,xe.upperFirst=Wo,xe.each=aa,xe.eachRight=oa,xe.first=Si,Jo(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:Ju(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=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(wa(Ju(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__=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=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}();Hn._=Kt,void 0===(u=function(){return Kt}.call(t,e,t,r))||(r.exports=u)}).call(this)}).call(this,e(76),e(480)(n))},478:function(n,t,e){"use strict";var r=e(0),u=Object(r.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=u},479:function(n,t,e){"use strict";e.d(t,"a",(function(){return i}));e(77),e(497),e(462),e(78);var r=e(499),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)}))}},480: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}},489:function(n,t,e){var r=e(30),u=e(54),i=e(27),a=e(26),o=e(490);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,D,g=i(t),_=u(g),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 _)&&(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}}},490:function(n,t,e){var r=e(491);n.exports=function(n,t){return new(r(n))(t)}},491:function(n,t,e){var r=e(13),u=e(492),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}},492:function(n,t,e){var r=e(23);n.exports=Array.isArray||function(n){return"Array"==r(n)}},498:function(n,t,e){"use strict";var r=e(0),u=e.n(r),i=e(454),a=e(447),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,")"))}},499:function(n,t,e){var r=e(500);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},500: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}},504:function(n,t,e){"use strict";var r=e(1),u=e(0),i=e.n(u),a=(e(454),e(498)),o=e(447),c=e.n(o),l=e(479),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))})))}},540:function(n,t,e){"use strict";e(29),e(22),e(21),e(52);var r=e(0),u=e.n(r),i=(e(452),e(462),e(454)),a=e(466),o=e.n(a),c=e(504),l=e(479),f=e(460),s=e(467);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),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"installation_guide"==n.category})),A=k?k.value:null,x=g.find((function(n){return"platform"==n.category})),j=x?x.value:null,O=g.find((function(n){return"source"==n.category})),N=O?O.value:null,B=g.find((function(n){return"sink"==n.category})),I=B?B.value:null,S=Object(f.a)().siteConfig.customFields.metadata,L=S.installation,R=S.sources,z=S.sinks,T=S.languages,W=S.frameworks,M=S.technologies,U=S.installation_guides,P=L.platforms,$=j&&P[j],q=N&&R[N],V=I&&z[I],G=b&&T.find((function(n){return n.name===b})),Z=w&&W.find((function(n){return n.name===w})),H=C&&M.find((function(n){return n.name===C})),K=A&&U.find((function(n){return n.name===A})),J=null!==($||q),Q=null!=V,Y=null;Z?Y=r?Z.dark_logo_path:Z.logo_path:H?Y=r?H.dark_logo_path:H.logo_path:K?Y=r?K.dark_logo_path:K.logo_path:G?Y=r?G.dark_logo_path:G.logo_path:$?Y=$.logo_path:q&&(Y=q.logo_path);var X=null;return V&&(X=V.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:D},h&&h+". ",p||D)),u.a.createElement("footer",null,Y&&u.a.createElement(o.a,{src:Y,className:"logo"}),!Y&&J&&u.a.createElement("div",{className:"logo"},u.a.createElement("i",{className:"feather icon-server"})),X&&u.a.createElement(o.a,{src:X,className:"logo"}),!X&&Q&&u.a.createElement("div",{className:"logo"},u.a.createElement("i",{className:"feather icon-server"})),!Y&&!X&&!J&&!Q&&u.a.createElement(c.a,{colorProfile:"guides",tags:d}),u.a.createElement("div",{className:"action"},"read now")))))},h=e(474),d=e(475),p=e.n(d),D=e(447),g=e.n(D);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:g()("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.7aaf2b9f.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{153:function(n,t,e){"use strict";e.r(t);e(454);var r=e(0),u=e.n(r),i=e(473),a=e(542),o=e(456);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})))}},449: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")},473:function(n,t,e){"use strict";e(483);var r=e(0),u=e.n(r),i=e(484),a=e(472),o=e(1),c=(e(474),e(475),e(485),e(456)),l=e(486),f=e(468),s=e.n(f),v=e(487),h=e.n(v),d=e(462),p=e(449),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(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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),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(z,{alt:f.alt,url:v})):u.a.createElement(z,{alt:f.alt,url:v})),u.a.createElement("small",null,a),u.a.createElement("br",null))))},W=e(488),M=e(489),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,D=n.keywords,g=(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}),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)))}},476:function(n,t,e){"use strict";var r=e(9),u=e(0),i=e.n(u),a=e(449),o=e.n(a),c=e(462),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)}}},477: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]",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*$/,V=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,G=/[\\^$.*+?()[\]{}|]/g,Z=RegExp(G.source),H=/^\s+|\s+$/g,K=/^\s+/,J=/\s+$/,Q=/\{(?:\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]",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,Vn=parseInt,Gn="object"==typeof n&&n&&n.Object===Object&&n,Zn="object"==typeof self&&self&&self.Object===Object&&self,Hn=Gn||Zn||Function("return this")(),Kn=t&&!t.nodeType&&t,Jn=Kn&&"object"==typeof r&&r&&!r.nodeType&&r,Qn=Jn&&Jn.exports===Kn,Yn=Qn&&Gn.process,Xn=function(){try{var n=Jn&&Jn.require&&Jn.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 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 Kt=function n(t){var e,r=(t=null==t?Hn:Kt.defaults(Hn.Object(),t,Kt.pick(Hn,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=Hn._,Nn=gn("^"+Fn.call(Cn).replace(G,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Bn=Qn?t.Buffer:void 0,Ln=t.Symbol,zn=t.Uint8Array,$n=Bn?Bn.allocUnsafe:void 0,Gn=Pt(Dn.getPrototypeOf,Dn),Zn=Dn.create,Kn=En.propertyIsEnumerable,Jn=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){}}(),Jt=t.clearTimeout!==Hn.clearTimeout&&t.clearTimeout,Qt=u&&u.now!==Hn.Date.now&&u.now,Yt=t.setTimeout!==Hn.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),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"),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($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 Je(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 gu(n,a)}else{var I=ei(n),S=I==h||I==d;if(Ra(n))return su(n,o);if(I==g||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 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,o)}}i||(i=new ze);var L=i.get(n);if(L)return L;i.set(n,a),Ha(n)?n.forEach((function(r){a.add(Je(r,t,e,r,n,i))})):qa(n)&&n.forEach((function(r,u){a.set(u,Je(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,Je(r,t,e,u,n,i))})),a}function Qe(n,t,e){var r=e.length;if(null==n)return!r;for(n=Dn(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=Qu(this,n).delete(n);return this.size-=t?1:0,t},Le.prototype.get=function(n){return Qu(this,n).get(n)},Le.prototype.has=function(n){return Qu(this,n).has(n)},Le.prototype.set=function(n,t){var e=Qu(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(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 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,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&&Jn.call(o,c,1),Jn.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)?Jn.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,Go),n+"")}function Wr(n){return We(jo(n))}function Mr(n,t){var e=jo(n);return wi(e,Ke(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&&!Ja(a)&&(e?a<=t:a=200){var l=t?null:zu(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=Jt||function(n){return Hn.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=Ja(n),a=void 0!==t,o=null===t,c=t==t,l=Ja(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=Dn(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"==Hu(a))var o=new Ne([],!0)}for(r=o?r:e;++r1&&m.reverse(),s&&l<_&&(m.length=l),this&&this!==Hn&&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=Qr(e),r=Qr(r)):(e=Jr(e),r=Jr(r)),u=n(e,r)}return u}}function Nu(n){return qu((function(t){return t=dt(t,Nt(Ju())),Tr((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?" ":Qr(t)).length;if(e<2)return e?zr(t,n):t;var r=zr(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(Q,"{\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 He(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,Ju(t,3))}function oa(n,t){return(Ba(n)?lt:tr)(n,Ju(t,3))}var ca=mu((function(n,t,e){Cn.call(n,e)?n[e].push(t):Ze(n,e,[t])}));var la=Tr((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,Ju(t,3))}var va=mu((function(n,t,e){n[e?0:1].push(t)}),(function(){return[[],[]]}));var ha=Tr((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=Qt||function(){return Hn.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 Da(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 ga=Tr((function(n,t,e){var r=1;if(e.length){var u=$t(e,Ku(ga));r|=32}return Wu(n,r,t,e,u)})),_a=Tr((function(n,t,e){var r=3;if(e.length){var u=$t(e,Ku(_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(g,t),s?d(n):o}function D(n){var e=n-l;return void 0===l||e>=t||e<0||v&&n-f>=a}function g(){var n=da();if(D(n))return _(n);c=mi(g,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=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)),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=Tr((function(n,t){return Ye(n,1,t)})),ba=Tr((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(Ju())):dt(ir(t,1),Nt(Ju()))).length;return Tr((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")&&!Kn.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,za=tt?Nt(tt):function(n){return $a(n)&&hr(n)==s};function Ta(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)==D}function Ga(n){if(!$a(n)||hr(n)!=g)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 Ha=ut?Nt(ut):function(n){return $a(n)&&ei(n)==m};function Ka(n){return"string"==typeof n||!Ba(n)&&$a(n)&&hr(n)==y}function Ja(n){return"symbol"==typeof n||$a(n)&&hr(n)==b}var Qa=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 Ka(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: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?Ke(eo(n),0,4294967295):0}function uo(n){if("number"==typeof n)return n;if(Ja(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(H,"");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?"":Qr(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(He);var vo=Tr((function(n,t){n=Dn(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=Je(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 Do(n,e)}))}(n,t)}));function ko(n,t){if(null==n)return{};var e=dt(Gu(n),(function(n){return[n]}));return t=Ju(t),Ir(n,e,(function(n,e){return t(n,e[0])}))}var Ao=Tu(yo),xo=Tu(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,zt).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 zo=Fu((function(n,t,e){return n+(e?" ":"")+Wo(t)}));var To=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 Tn.test(n)}(n)?function(n){return n.match(Rn)||[]}(n):function(n){return n.match(nn)||[]}(n):n.match(t)||[]}var Uo=Tr((function(n,t){try{return at(n,void 0,t)}catch(e){return Ta(e)?e:new hn(e)}})),Po=qu((function(n,t){return ct(t,(function(t){t=Ci(t),Ze(n,t,ga(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:Je(n,1))}var Ho=Tr((function(n,t){return function(e){return _r(e,n,t)}})),Ko=Tr((function(n,t){return function(e){return _r(n,e,t)}}));function Jo(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__=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 Qo(){}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=Da,xe.bind=ga,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=Qr(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),Tr((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,Ju(t,3),!1,!0):[]},xe.takeWhile=function(n,t){return n&&n.length?tu(n,Ju(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):Ja(n)?[n]:gu(Fi(ao(n)))},xe.toPlainObject=io,xe.transform=function(n,t,e){var r=Ba(n),u=r||Ra(n)||Qa(n);if(t=Ju(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,Ju(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=Hi,xe.words=Mo,xe.wrap=function(n,t){return Ca(au(t),n)},xe.xor=Ki,xe.xorBy=Ji,xe.xorWith=Qi,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,Jo(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),Ke(uo(n),t,e)},xe.clone=function(n){return Je(n,4)},xe.cloneDeep=function(n){return Je(n,5)},xe.cloneDeepWith=function(n,t){return Je(n,5,t="function"==typeof t?t:void 0)},xe.cloneWith=function(n,t){return Je(n,4,t="function"==typeof t?t:void 0)},xe.conformsTo=function(n,t){return null==t||Qe(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=Qr(t);var r=n.length,u=e=void 0===e?r:Ke(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(z,Tt):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,Ju(t,3))},xe.find=ua,xe.findIndex=Ni,xe.findKey=function(n,t){return yt(n,Ju(t,3),cr)},xe.findLast=ia,xe.findLastIndex=Bi,xe.findLastKey=function(n,t){return yt(n,Ju(t,3),lr)},xe.floor=lc,xe.forEach=aa,xe.forEachRight=oa,xe.forIn=function(n,t){return null==n?n:ar(n,Ju(t,3),bo)},xe.forInRight=function(n,t){return null==n?n:or(n,Ju(t,3),bo)},xe.forOwn=function(n,t){return n&&cr(n,Ju(t,3))},xe.forOwnRight=function(n,t){return n&&lr(n,Ju(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=Do,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)),Ka(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=Ha,xe.isString=Ka,xe.isSymbol=Ja,xe.isTypedArray=Qa,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=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=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,Ju(t,2),dr):void 0},xe.mean=function(n){return Ct(n,Go)},xe.meanBy=function(n,t){return Ct(n,Ju(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,Ju(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 Hn._===this&&(Hn._=On),this},xe.noop=Qo,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)?Dt:xt,u=arguments.length<3;return r(n,Ju(t,4),e,u,nr)},xe.reduceRight=function(n,t,e){var r=Ba(n)?gt:xt,u=arguments.length<3;return r(n,Ju(t,4),e,u,tr)},xe.repeat=function(n,t,e){return t=(e?oi(n,t,e):void 0===t)?1:eo(t),zr(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=Ju(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=gn(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(Qr(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))&&T.test(n)?n.replace(R,Ht):n},xe.uniqueId=function(n){var t=++kn;return ao(n)+t},xe.upperCase=To,xe.upperFirst=Wo,xe.each=aa,xe.eachRight=oa,xe.first=Si,Jo(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:Ju(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=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(wa(Ju(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__=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=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}();Hn._=Kt,void 0===(u=function(){return Kt}.call(t,e,t,r))||(r.exports=u)}).call(this)}).call(this,e(76),e(482)(n))},480:function(n,t,e){"use strict";var r=e(0),u=Object(r.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=u},481:function(n,t,e){"use strict";e.d(t,"a",(function(){return i}));e(77),e(499),e(464),e(78);var r=e(501),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)}))}},482: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}},491:function(n,t,e){var r=e(30),u=e(54),i=e(27),a=e(26),o=e(492);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,D,g=i(t),_=u(g),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 _)&&(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}}},492:function(n,t,e){var r=e(493);n.exports=function(n,t){return new(r(n))(t)}},493:function(n,t,e){var r=e(13),u=e(494),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}},494:function(n,t,e){var r=e(23);n.exports=Array.isArray||function(n){return"Array"==r(n)}},500:function(n,t,e){"use strict";var r=e(0),u=e.n(r),i=e(456),a=e(449),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,")"))}},501:function(n,t,e){var r=e(502);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},502: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}},506:function(n,t,e){"use strict";var r=e(1),u=e(0),i=e.n(u),a=(e(456),e(500)),o=e(449),c=e.n(o),l=e(481),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))})))}},542:function(n,t,e){"use strict";e(29),e(22),e(21),e(52);var r=e(0),u=e.n(r),i=(e(454),e(464),e(456)),a=e(468),o=e.n(a),c=e(506),l=e(481),f=e(462),s=e(469);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),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"installation_guide"==n.category})),A=k?k.value:null,x=g.find((function(n){return"platform"==n.category})),j=x?x.value:null,O=g.find((function(n){return"source"==n.category})),N=O?O.value:null,B=g.find((function(n){return"sink"==n.category})),I=B?B.value:null,S=Object(f.a)().siteConfig.customFields.metadata,L=S.installation,R=S.sources,z=S.sinks,T=S.languages,W=S.frameworks,M=S.technologies,U=S.installation_guides,P=L.platforms,$=j&&P[j],q=N&&R[N],V=I&&z[I],G=b&&T.find((function(n){return n.name===b})),Z=w&&W.find((function(n){return n.name===w})),H=C&&M.find((function(n){return n.name===C})),K=A&&U.find((function(n){return n.name===A})),J=null!==($||q),Q=null!=V,Y=null;Z?Y=r?Z.dark_logo_path:Z.logo_path:H?Y=r?H.dark_logo_path:H.logo_path:K?Y=r?K.dark_logo_path:K.logo_path:G?Y=r?G.dark_logo_path:G.logo_path:$?Y=$.logo_path:q&&(Y=q.logo_path);var X=null;return V&&(X=V.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:D},h&&h+". ",p||D)),u.a.createElement("footer",null,Y&&u.a.createElement(o.a,{src:Y,className:"logo"}),!Y&&J&&u.a.createElement("div",{className:"logo"},u.a.createElement("i",{className:"feather icon-server"})),X&&u.a.createElement(o.a,{src:X,className:"logo"}),!X&&Q&&u.a.createElement("div",{className:"logo"},u.a.createElement("i",{className:"feather icon-server"})),!Y&&!X&&!J&&!Q&&u.a.createElement(c.a,{colorProfile:"guides",tags:d}),u.a.createElement("div",{className:"action"},"read now")))))},h=e(476),d=e(477),p=e.n(d),D=e(449),g=e.n(D);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:g()("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.9091d5cc.js.LICENSE.txt b/004ec9e5.7aaf2b9f.js.LICENSE.txt similarity index 100% rename from 004ec9e5.9091d5cc.js.LICENSE.txt rename to 004ec9e5.7aaf2b9f.js.LICENSE.txt diff --git a/02ec211a.b7b5dc04.js b/02ec211a.5d7f3ad9.js similarity index 96% rename from 02ec211a.b7b5dc04.js rename to 02ec211a.5d7f3ad9.js index 6f106b1edd..da41735eb2 100644 --- a/02ec211a.b7b5dc04.js +++ b/02ec211a.5d7f3ad9.js @@ -1,2 +1,2 @@ -/*! For license information please see 02ec211a.b7b5dc04.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(449)),r=n(456),l=(n(457),n(448)),c=n(453),s={last_modified_on:"2024-07-30",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:"Advanced Settings",id:"advanced-settings",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 to configure your helm chart but you can create an override in the next two sections."),Object(i.b)("p",null,"In the override as file section, define the location of the file containing the override you want to define for the values of this chart."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Git Repository ")),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,Object(i.b)("strong",{parentName:"p"}," Raw YAML ")),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:"warning",mdxType:"Alert"},Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Git repository source is recommended as the raw yaml is not versioned."),Object(i.b)("li",{parentName:"ul"},"On both file types you can use your environment variables in your chart. Check ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/helm/#using-the-environment-variables-in-your-chart"}),"the section below"),".")))),Object(i.b)("li",null,Object(i.b)("p",null,"if you want to specify one by one your overrides or define additional overrides on top of the one available in your override file, 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)("p",null,"Add a new variable by declaring:"),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:"warning",mdxType:"Alert"},Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"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",{parentName:"ul"},"You can use your environment variables in your chart. Check ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/helm/#using-the-environment-variables-in-your-chart"}),"the section below"),".")))),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)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"To let you access every Qovery functionality, additional Qovery labels and annotations are automatically injected in some of the Kubernetes objects deployed within your 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. You can add a new container registry by clicking on ",Object(i.b)("inlineCode",{parentName:"li"},"New helm repository"),"."),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 defined within the creation flow."),Object(i.b)("h4",{id:"override-as-file"},"Override as file"),Object(i.b)("p",null,"Define the location of the file containing the override you want to define for the values of this chart."),Object(i.b)("p",null,"Select the source of your override:"),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Git Repository "),"\nIf 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,Object(i.b)("strong",{parentName:"p"}," Raw YAML "),"\nIf 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)("p",null,"On both file types you can use your environment variables in your chart. Check ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/#using-the-environment-variables-in-your-chart"}),"the section below"),"."),Object(i.b)("h4",{id:"override-as-arguments"},"Override as arguments"),Object(i.b)("p",null,"if you want to specify one by one your overrides or define additional overrides on top of the one available in your override file, 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)("p",null,"Add a new variable by declaring:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Override type: select the type of your variable. For more information, have a look at the Helm documentation"),Object(i.b)("li",{parentName:"ul"},"Variable: the variable name"),Object(i.b)("li",{parentName:"ul"},"Value")),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},"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)("p",null,"You can use your environment variables in your chart. Check ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/#using-the-environment-variables-in-your-chart"}),"the section below"),"."),Object(i.b)("h4",{id:"using-the-environment-variables-in-your-chart"},"Using the environment variables in your chart"),Object(i.b)("p",null,"Qovery allows you to use the following macros within your override file. These macros will be automatically replaced by Qovery during the deployment phase, allowing you to access additional functionalities."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Access to the Qovery environment variables ")),Object(i.b)("p",null,"Macro: ",Object(i.b)("inlineCode",{parentName:"p"},"qovery.env.")),Object(i.b)("p",null,"It allows you to access the value of an environment variable or secret stored within Qovery. This is helpful when your deployed helm chart needs to access a secret or an environment variable available in Qovery."),Object(i.b)("p",null,"Example: "),Object(i.b)("p",null,"On Qovery we have created a database and created two aliases for the database url (DB_URL) and, the database password (DB_PASSWORD). Here an example on how the helm chart can access these environment variables and let your service point to the right database:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-yaml"}),"postgres:\n url: qovery.env.DB_URL\n password: qovery.env.DB_PASSWORD\n")),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)("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 and assign a domain to your application (See ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"#qovery-provided-domains"}),"this section")," to know more). You can customize the domain assigned to your application via the ",Object(i.b)("inlineCode",{parentName:"p"},"Domain")," section in the settings (see ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"#custom-domains"}),"this section")," to know more)."),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, you can customize it from the "Domain" section within the helm services settings.'),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"),"). See ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"#qovery-provided-domains"}),"this section")," to know more about these domains.")),Object(i.b)("p",null,"In both cases, you can assign the new custom domain by pressing 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 entry (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 a 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,"After re-deploying the service, 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)(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)("p",null,Object(i.b)("strong",{parentName:"p"}," Special case - domain behind a CDN ")),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 enable the option ",Object(i.b)("inlineCode",{parentName:"p"},"Domain behind a CDN"),' and 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)("p",null,"If you are using Cloudflare to manage your CDN, we can also manage automatically your custom domain configuration via a wildcard domain setup for the whole cluster. Check our ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#use-custom-domain-and-wildcard-tls-for-the-whole-cluster-beta"}),"documentation here")),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:"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)("h3",{id:"advanced-settings"},"Advanced Settings"),Object(i.b)("p",null,"You can further customize the service behaviour via the service advanced settings. Check ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/advanced-settings/"}),"this documentation")," to know more."),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var o=n(0),a=n.n(o),i=n(448);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)}},454:function(e,t,n){"use strict";var o=n(1),a=n(0),i=n.n(a),r=n(39),l=n(458),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}))}},455:function(e,t,n){"use strict";var o=n(459),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("&"):""}},456:function(e,t,n){"use strict";var o=n(0),a=n.n(o),i=(n(447),n(455)),r=n.n(i);n(133);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"),"."))}},457:function(e,t,n){"use strict";var o=n(0),a=n.n(o),i=n(454),r=n(447),l=n.n(r);n(134);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)}},458:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},459: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 02ec211a.5d7f3ad9.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(451)),r=n(458),l=(n(459),n(450)),c=n(455),s={last_modified_on:"2024-07-30",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:"Advanced Settings",id:"advanced-settings",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 to configure your helm chart but you can create an override in the next two sections."),Object(i.b)("p",null,"In the override as file section, define the location of the file containing the override you want to define for the values of this chart."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Git Repository ")),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,Object(i.b)("strong",{parentName:"p"}," Raw YAML ")),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:"warning",mdxType:"Alert"},Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Git repository source is recommended as the raw yaml is not versioned."),Object(i.b)("li",{parentName:"ul"},"On both file types you can use your environment variables in your chart. Check ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/helm/#using-the-environment-variables-in-your-chart"}),"the section below"),".")))),Object(i.b)("li",null,Object(i.b)("p",null,"if you want to specify one by one your overrides or define additional overrides on top of the one available in your override file, 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)("p",null,"Add a new variable by declaring:"),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:"warning",mdxType:"Alert"},Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"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",{parentName:"ul"},"You can use your environment variables in your chart. Check ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/helm/#using-the-environment-variables-in-your-chart"}),"the section below"),".")))),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)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"To let you access every Qovery functionality, additional Qovery labels and annotations are automatically injected in some of the Kubernetes objects deployed within your 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. You can add a new container registry by clicking on ",Object(i.b)("inlineCode",{parentName:"li"},"New helm repository"),"."),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 defined within the creation flow."),Object(i.b)("h4",{id:"override-as-file"},"Override as file"),Object(i.b)("p",null,"Define the location of the file containing the override you want to define for the values of this chart."),Object(i.b)("p",null,"Select the source of your override:"),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Git Repository "),"\nIf 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,Object(i.b)("strong",{parentName:"p"}," Raw YAML "),"\nIf 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)("p",null,"On both file types you can use your environment variables in your chart. Check ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/#using-the-environment-variables-in-your-chart"}),"the section below"),"."),Object(i.b)("h4",{id:"override-as-arguments"},"Override as arguments"),Object(i.b)("p",null,"if you want to specify one by one your overrides or define additional overrides on top of the one available in your override file, 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)("p",null,"Add a new variable by declaring:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"Override type: select the type of your variable. For more information, have a look at the Helm documentation"),Object(i.b)("li",{parentName:"ul"},"Variable: the variable name"),Object(i.b)("li",{parentName:"ul"},"Value")),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},"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)("p",null,"You can use your environment variables in your chart. Check ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/#using-the-environment-variables-in-your-chart"}),"the section below"),"."),Object(i.b)("h4",{id:"using-the-environment-variables-in-your-chart"},"Using the environment variables in your chart"),Object(i.b)("p",null,"Qovery allows you to use the following macros within your override file. These macros will be automatically replaced by Qovery during the deployment phase, allowing you to access additional functionalities."),Object(i.b)("p",null,Object(i.b)("strong",{parentName:"p"}," Access to the Qovery environment variables ")),Object(i.b)("p",null,"Macro: ",Object(i.b)("inlineCode",{parentName:"p"},"qovery.env.")),Object(i.b)("p",null,"It allows you to access the value of an environment variable or secret stored within Qovery. This is helpful when your deployed helm chart needs to access a secret or an environment variable available in Qovery."),Object(i.b)("p",null,"Example: "),Object(i.b)("p",null,"On Qovery we have created a database and created two aliases for the database url (DB_URL) and, the database password (DB_PASSWORD). Here an example on how the helm chart can access these environment variables and let your service point to the right database:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-yaml"}),"postgres:\n url: qovery.env.DB_URL\n password: qovery.env.DB_PASSWORD\n")),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)("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 and assign a domain to your application (See ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"#qovery-provided-domains"}),"this section")," to know more). You can customize the domain assigned to your application via the ",Object(i.b)("inlineCode",{parentName:"p"},"Domain")," section in the settings (see ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"#custom-domains"}),"this section")," to know more)."),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, you can customize it from the "Domain" section within the helm services settings.'),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"),"). See ",Object(i.b)("a",Object(o.a)({parentName:"li"},{href:"#qovery-provided-domains"}),"this section")," to know more about these domains.")),Object(i.b)("p",null,"In both cases, you can assign the new custom domain by pressing 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 entry (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 a 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,"After re-deploying the service, 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)(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)("p",null,Object(i.b)("strong",{parentName:"p"}," Special case - domain behind a CDN ")),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 enable the option ",Object(i.b)("inlineCode",{parentName:"p"},"Domain behind a CDN"),' and 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)("p",null,"If you are using Cloudflare to manage your CDN, we can also manage automatically your custom domain configuration via a wildcard domain setup for the whole cluster. Check our ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#use-custom-domain-and-wildcard-tls-for-the-whole-cluster-beta"}),"documentation here")),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:"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)("h3",{id:"advanced-settings"},"Advanced Settings"),Object(i.b)("p",null,"You can further customize the service behaviour via the service advanced settings. Check ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/advanced-settings/"}),"this documentation")," to know more."),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var o=n(0),a=n.n(o),i=n(450);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)}},456:function(e,t,n){"use strict";var o=n(1),a=n(0),i=n.n(a),r=n(39),l=n(460),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}))}},457:function(e,t,n){"use strict";var o=n(461),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("&"):""}},458:function(e,t,n){"use strict";var o=n(0),a=n.n(o),i=(n(449),n(457)),r=n.n(i);n(133);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"),"."))}},459:function(e,t,n){"use strict";var o=n(0),a=n.n(o),i=n(456),r=n(449),l=n.n(r);n(134);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)}},460:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},461: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/02ec211a.b7b5dc04.js.LICENSE.txt b/02ec211a.5d7f3ad9.js.LICENSE.txt similarity index 100% rename from 02ec211a.b7b5dc04.js.LICENSE.txt rename to 02ec211a.5d7f3ad9.js.LICENSE.txt diff --git a/03d003d1.ce8e0419.js b/03d003d1.8a18c61b.js similarity index 93% rename from 03d003d1.ce8e0419.js rename to 03d003d1.8a18c61b.js index 09bc102579..9271fae509 100644 --- a/03d003d1.ce8e0419.js +++ b/03d003d1.8a18c61b.js @@ -1,2 +1,2 @@ -/*! For license information please see 03d003d1.ce8e0419.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(449)),i=(n(456),n(453),n(448),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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.8a18c61b.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(451)),i=(n(458),n(455),n(450),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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.ce8e0419.js.LICENSE.txt b/03d003d1.8a18c61b.js.LICENSE.txt similarity index 100% rename from 03d003d1.ce8e0419.js.LICENSE.txt rename to 03d003d1.8a18c61b.js.LICENSE.txt diff --git a/03dbc155.89355e30.js b/03dbc155.89c09683.js similarity index 98% rename from 03dbc155.89355e30.js rename to 03dbc155.89c09683.js index 34ba580858..30e91a76c4 100644 --- a/03dbc155.89355e30.js +++ b/03dbc155.89c09683.js @@ -1 +1 @@ -(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(449)),l=a(448),i=a(464),c=a(461),b=a(453),u={last_modified_on:"2024-05-16",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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)(l.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"This guide also work for migrating your application from Heroku to GCP, Azure, Scaleway and ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/"}),"all cloud provider")," supported by Qovery.")),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/installation-guide/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,"Absolutely, you can connect directly to your application with a shell by clicking on the Qovery cloud shell button (1):"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/qovery_cloud_shell.png",alt:"Qovery Cloud Shell"})),Object(r.b)("p",null,"Then you just have to select the pod (2) and the container (3)."),Object(r.b)("p",null,"You can also check out our ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/#shell"}),"CLI")," and the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery shell")," command."),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},448:function(e,t,a){"use strict";a(450);var o=a(0),n=a.n(o),r=a(447),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)}},452: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""}}})},453:function(e,t,a){"use strict";a(452);var o=a(0),n=a.n(o),r=a(448);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)}},461:function(e,t,a){"use strict";var o=a(1),n=(a(465),a(462),a(52),a(29),a(22),a(21),a(0)),r=a.n(n),l=a(469),i=a(447),c=a.n(i),b=a(455),u=a.n(b),s=a(468),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])}},464: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(451)),l=a(450),i=a(466),c=a(463),b=a(455),u={last_modified_on:"2024-05-16",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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)(l.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"This guide also work for migrating your application from Heroku to GCP, Azure, Scaleway and ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/"}),"all cloud provider")," supported by Qovery.")),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/installation-guide/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,"Absolutely, you can connect directly to your application with a shell by clicking on the Qovery cloud shell button (1):"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/qovery_cloud_shell.png",alt:"Qovery Cloud Shell"})),Object(r.b)("p",null,"Then you just have to select the pod (2) and the container (3)."),Object(r.b)("p",null,"You can also check out our ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/#shell"}),"CLI")," and the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery shell")," command."),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},450:function(e,t,a){"use strict";a(452);var o=a(0),n=a.n(o),r=a(449),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)}},454: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""}}})},455:function(e,t,a){"use strict";a(454);var o=a(0),n=a.n(o),r=a(450);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)}},463:function(e,t,a){"use strict";var o=a(1),n=(a(467),a(464),a(52),a(29),a(22),a(21),a(0)),r=a.n(n),l=a(471),i=a(449),c=a.n(i),b=a(457),u=a.n(b),s=a(470),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])}},466: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/04b748dc.912702df.js b/04b748dc.6e320242.js similarity index 92% rename from 04b748dc.912702df.js rename to 04b748dc.6e320242.js index d69d4c3cff..ba8536980d 100644 --- a/04b748dc.912702df.js +++ b/04b748dc.6e320242.js @@ -1,2 +1,2 @@ -/*! For license information please see 04b748dc.912702df.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 l})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return d}));var r=n(1),a=n(9),o=(n(0),n(449)),i=n(456),s=n(448),c=n(453),l={last_modified_on:"2024-03-21",title:"Create Credentials",description:"Generate AWS credentials for Qovery"},u={id:"getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials",title:"Create Credentials",description:"Generate AWS credentials for Qovery",source:"@site/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials.md",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials",sidebar:"docs",previous:{title:"Quickstart",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart"},next:{title:"Infrastructure",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure"}},b=[{value:"Generate AWS credentials",id:"generate-aws-credentials",children:[{value:"Install a new cluster on Qovery",id:"install-a-new-cluster-on-qovery",children:[]}]},{value:"Next steps",id:"next-steps",children:[]}],p={rightToc:b};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,"This guide will help you to create your Amazon Web Services (AWS) credentials for Qovery. Those credentials will be used to create a Kubernetes cluster, a dedicated VPC and a few services on your AWS account. Refer to our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure/"}),"Infrastructure")," page to learn more about the infrastructure created by Qovery."),Object(o.b)(c.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have an AWS account"))),Object(o.b)("h2",{id:"generate-aws-credentials"},"Generate AWS credentials"),Object(o.b)(i.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(r.a)({parentName:"p"},{href:"https://console.aws.amazon.com"}),"Connect to your AWS 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/aws/aws-my-security-credentials.png"})),Object(o.b)("li",null,Object(o.b)("p",null,"Create ",Object(o.b)("inlineCode",{parentName:"p"},"Admins")," group ",Object(o.b)("strong",{parentName:"p"},"without any permissions")),Object(o.b)(s.a,{type:"warning",mdxType:"Alert"},Object(o.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(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cluster-advanced-settings/#iam"}),"aws.iam.admin_group")," BEFORE launching the cluster installation process")),Object(o.b)("img",{src:"/img/aws/aws-create-group-1.jpg"}),Object(o.b)("img",{src:"/img/aws/aws-create-group-2.png"}),Object(o.b)("img",{src:"/img/aws/aws-create-group-3.png"})),Object(o.b)("li",null,Object(o.b)("p",null,"Create one IAM user called ",Object(o.b)("inlineCode",{parentName:"p"},"qovery"),"."),Object(o.b)("img",{src:"/img/aws/aws-create-user-1.jpg"}),Object(o.b)("img",{src:"/img/aws/aws-create-user-2.png"}),Object(o.b)("img",{src:"/img/aws/aws-create-user-3.jpg"}),Object(o.b)("img",{src:"/img/aws/aws-create-user-4.png"})),Object(o.b)("li",null,Object(o.b)("p",null,"Setup",Object(o.b)("a",{href:"/files/qovery-iam-aws.json"}," IAM permissions")," to the ",Object(o.b)("inlineCode",{parentName:"p"},"qovery")," user."),Object(o.b)(s.a,{type:"warning",mdxType:"Alert"},Object(o.b)("a",{href:"/files/qovery-iam-aws.json"},"Download IAM permissions JSON"),Object(o.b)("hr",null),Object(o.b)("p",null,"Or copy it from below:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Effect": "Allow",\n "Action": [\n "iam:*",\n "s3:ListAllMyBuckets",\n "cloudwatch:*",\n "autoscaling:*",\n "application-autoscaling:*",\n "elasticloadbalancing:*",\n "organizations:DescribeAccount",\n "organizations:DescribeOrganization",\n "organizations:DescribeOrganizationalUnit",\n "organizations:DescribePolicy",\n "organizations:ListChildren",\n "organizations:ListParents",\n "organizations:ListPoliciesForTarget",\n "organizations:ListRoots",\n "organizations:ListPolicies",\n "organizations:ListTargetsForPolicy",\n "dynamodb:*",\n "ecr:*",\n "ec2:*",\n "elasticache:*",\n "cloudtrail:LookupEvents",\n "kms:DescribeKey",\n "kms:ListAliases",\n "dynamodb:*",\n "tag:GetResources",\n "rds:*",\n "ecs:*",\n "eks:*",\n "logs:*",\n "events:DescribeRule",\n "events:DeleteRule",\n "events:ListRuleNamesByTarget",\n "events:ListTargetsByRule",\n "events:PutRule",\n "events:PutTargets",\n "es:AddTags",\n "es:RemoveTags",\n "es:ListTags",\n "es:DeleteElasticsearchDomain",\n "es:DescribeElasticsearchDomain",\n "es:CreateElasticsearchDomain",\n "events:RemoveTargets",\n "kms:*",\n "events:TagResource",\n "events:ListTagsForResource"\n ],\n "Resource": "*"\n },\n {\n "Action": [\n "s3:*",\n "sqs:*"\n ],\n "Effect": "Allow",\n "Resource": [\n "arn:aws:s3:::qovery*",\n "arn:aws:s3:::qovery*/*",\n "arn:aws:sqs:*:*:qovery*",\n "arn:aws:sqs:*:*:qovery*/*"\n ]\n }\n ]\n}\n'))),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Then, follow the arrows in AWS console to create AWS credentials with required IAM permissions:")),Object(o.b)("img",{src:"/img/aws/aws-add-policy-1.jpg"}),Object(o.b)("img",{src:"/img/aws/aws-add-policy-2.png"}),Object(o.b)("img",{src:"/img/aws/aws-add-policy-3.jpg"}),Object(o.b)("img",{src:"/img/aws/aws-add-policy-4.jpg"})),Object(o.b)("li",null,Object(o.b)("p",null,"To create an ",Object(o.b)("inlineCode",{parentName:"p"},"access key id")," and ",Object(o.b)("inlineCode",{parentName:"p"},"secret access key"),", go to the Security Credentials tab of the ",Object(o.b)("inlineCode",{parentName:"p"},"Qovery")," user and press ",Object(o.b)("inlineCode",{parentName:"p"},"Create access key")),Object(o.b)("img",{src:"/img/aws/aws-create-credentials-1.png"}),Object(o.b)("img",{src:"/img/aws/aws-create-credentials-2.png"}),Object(o.b)("img",{src:"/img/aws/aws-create-credentials-3.png"}),Object(o.b)("p",null,"You can now save the ",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/aws/aws-create-credentials-4.png"})))),Object(o.b)("p",null,"Well done!! You now have your AWS ",Object(o.b)("inlineCode",{parentName:"p"},"access key id")," and ",Object(o.b)("inlineCode",{parentName:"p"},"secret access key")," and your permissions are setups; It is time to connect Qovery to your AWS 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(r.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)("h2",{id:"next-steps"},"Next steps"),Object(o.b)("p",null,"Now you can use your AWS account to deploy your applications on Qovery. You can also link other Cloud providers to your organization."))}d.isMDXComponent=!0},447: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):s({},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,i=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),b=u(n),d=r,m=b["".concat(i,".").concat(d)]||b[d]||p[d]||o;return n?a.a.createElement(m,s({ref:t},l,{components:n})):a.a.createElement(m,s({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 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 l=2;l1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,l=void 0===c?n:a(c,n);l>s;)t[s++]=e;return t}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,s="undefined"!=typeof window?window.location:null,c={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"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(c),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:l,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"),"."))}},459: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 04b748dc.6e320242.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 l})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return d}));var r=n(1),a=n(9),o=(n(0),n(451)),i=n(458),s=n(450),c=n(455),l={last_modified_on:"2024-03-21",title:"Create Credentials",description:"Generate AWS credentials for Qovery"},u={id:"getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials",title:"Create Credentials",description:"Generate AWS credentials for Qovery",source:"@site/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials.md",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials",sidebar:"docs",previous:{title:"Quickstart",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart"},next:{title:"Infrastructure",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure"}},b=[{value:"Generate AWS credentials",id:"generate-aws-credentials",children:[{value:"Install a new cluster on Qovery",id:"install-a-new-cluster-on-qovery",children:[]}]},{value:"Next steps",id:"next-steps",children:[]}],p={rightToc:b};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,"This guide will help you to create your Amazon Web Services (AWS) credentials for Qovery. Those credentials will be used to create a Kubernetes cluster, a dedicated VPC and a few services on your AWS account. Refer to our ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure/"}),"Infrastructure")," page to learn more about the infrastructure created by Qovery."),Object(o.b)(c.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have an AWS account"))),Object(o.b)("h2",{id:"generate-aws-credentials"},"Generate AWS credentials"),Object(o.b)(i.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(r.a)({parentName:"p"},{href:"https://console.aws.amazon.com"}),"Connect to your AWS 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/aws/aws-my-security-credentials.png"})),Object(o.b)("li",null,Object(o.b)("p",null,"Create ",Object(o.b)("inlineCode",{parentName:"p"},"Admins")," group ",Object(o.b)("strong",{parentName:"p"},"without any permissions")),Object(o.b)(s.a,{type:"warning",mdxType:"Alert"},Object(o.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(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cluster-advanced-settings/#iam"}),"aws.iam.admin_group")," BEFORE launching the cluster installation process")),Object(o.b)("img",{src:"/img/aws/aws-create-group-1.jpg"}),Object(o.b)("img",{src:"/img/aws/aws-create-group-2.png"}),Object(o.b)("img",{src:"/img/aws/aws-create-group-3.png"})),Object(o.b)("li",null,Object(o.b)("p",null,"Create one IAM user called ",Object(o.b)("inlineCode",{parentName:"p"},"qovery"),"."),Object(o.b)("img",{src:"/img/aws/aws-create-user-1.jpg"}),Object(o.b)("img",{src:"/img/aws/aws-create-user-2.png"}),Object(o.b)("img",{src:"/img/aws/aws-create-user-3.jpg"}),Object(o.b)("img",{src:"/img/aws/aws-create-user-4.png"})),Object(o.b)("li",null,Object(o.b)("p",null,"Setup",Object(o.b)("a",{href:"/files/qovery-iam-aws.json"}," IAM permissions")," to the ",Object(o.b)("inlineCode",{parentName:"p"},"qovery")," user."),Object(o.b)(s.a,{type:"warning",mdxType:"Alert"},Object(o.b)("a",{href:"/files/qovery-iam-aws.json"},"Download IAM permissions JSON"),Object(o.b)("hr",null),Object(o.b)("p",null,"Or copy it from below:"),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-json"}),'{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Effect": "Allow",\n "Action": [\n "iam:*",\n "s3:ListAllMyBuckets",\n "cloudwatch:*",\n "autoscaling:*",\n "application-autoscaling:*",\n "elasticloadbalancing:*",\n "organizations:DescribeAccount",\n "organizations:DescribeOrganization",\n "organizations:DescribeOrganizationalUnit",\n "organizations:DescribePolicy",\n "organizations:ListChildren",\n "organizations:ListParents",\n "organizations:ListPoliciesForTarget",\n "organizations:ListRoots",\n "organizations:ListPolicies",\n "organizations:ListTargetsForPolicy",\n "dynamodb:*",\n "ecr:*",\n "ec2:*",\n "elasticache:*",\n "cloudtrail:LookupEvents",\n "kms:DescribeKey",\n "kms:ListAliases",\n "dynamodb:*",\n "tag:GetResources",\n "rds:*",\n "ecs:*",\n "eks:*",\n "logs:*",\n "events:DescribeRule",\n "events:DeleteRule",\n "events:ListRuleNamesByTarget",\n "events:ListTargetsByRule",\n "events:PutRule",\n "events:PutTargets",\n "es:AddTags",\n "es:RemoveTags",\n "es:ListTags",\n "es:DeleteElasticsearchDomain",\n "es:DescribeElasticsearchDomain",\n "es:CreateElasticsearchDomain",\n "events:RemoveTargets",\n "kms:*",\n "events:TagResource",\n "events:ListTagsForResource"\n ],\n "Resource": "*"\n },\n {\n "Action": [\n "s3:*",\n "sqs:*"\n ],\n "Effect": "Allow",\n "Resource": [\n "arn:aws:s3:::qovery*",\n "arn:aws:s3:::qovery*/*",\n "arn:aws:sqs:*:*:qovery*",\n "arn:aws:sqs:*:*:qovery*/*"\n ]\n }\n ]\n}\n'))),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Then, follow the arrows in AWS console to create AWS credentials with required IAM permissions:")),Object(o.b)("img",{src:"/img/aws/aws-add-policy-1.jpg"}),Object(o.b)("img",{src:"/img/aws/aws-add-policy-2.png"}),Object(o.b)("img",{src:"/img/aws/aws-add-policy-3.jpg"}),Object(o.b)("img",{src:"/img/aws/aws-add-policy-4.jpg"})),Object(o.b)("li",null,Object(o.b)("p",null,"To create an ",Object(o.b)("inlineCode",{parentName:"p"},"access key id")," and ",Object(o.b)("inlineCode",{parentName:"p"},"secret access key"),", go to the Security Credentials tab of the ",Object(o.b)("inlineCode",{parentName:"p"},"Qovery")," user and press ",Object(o.b)("inlineCode",{parentName:"p"},"Create access key")),Object(o.b)("img",{src:"/img/aws/aws-create-credentials-1.png"}),Object(o.b)("img",{src:"/img/aws/aws-create-credentials-2.png"}),Object(o.b)("img",{src:"/img/aws/aws-create-credentials-3.png"}),Object(o.b)("p",null,"You can now save the ",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/aws/aws-create-credentials-4.png"})))),Object(o.b)("p",null,"Well done!! You now have your AWS ",Object(o.b)("inlineCode",{parentName:"p"},"access key id")," and ",Object(o.b)("inlineCode",{parentName:"p"},"secret access key")," and your permissions are setups; It is time to connect Qovery to your AWS 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(r.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)("h2",{id:"next-steps"},"Next steps"),Object(o.b)("p",null,"Now you can use your AWS account to deploy your applications on Qovery. You can also link other Cloud providers to your organization."))}d.isMDXComponent=!0},449: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):s({},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,i=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),b=u(n),d=r,m=b["".concat(i,".").concat(d)]||b[d]||p[d]||o;return n?a.a.createElement(m,s({ref:t},l,{components:n})):a.a.createElement(m,s({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 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 l=2;l1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,l=void 0===c?n:a(c,n);l>s;)t[s++]=e;return t}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,s="undefined"!=typeof window?window.location:null,c={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"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(c),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:l,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"),"."))}},461: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/04b748dc.912702df.js.LICENSE.txt b/04b748dc.6e320242.js.LICENSE.txt similarity index 100% rename from 04b748dc.912702df.js.LICENSE.txt rename to 04b748dc.6e320242.js.LICENSE.txt diff --git a/05049f86.2665fa95.js b/05049f86.4f4dfc9f.js similarity index 90% rename from 05049f86.2665fa95.js rename to 05049f86.4f4dfc9f.js index 6dd595a6db..ad8309c58a 100644 --- a/05049f86.2665fa95.js +++ b/05049f86.4f4dfc9f.js @@ -1,2 +1,2 @@ -/*! For license information please see 05049f86.2665fa95.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{158: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(449)),i=(r(456),r(453),r(448)),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},447: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}},452: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""}}})},453:function(e,t,r){"use strict";r(452);var n=r(0),a=r.n(n),o=r(448);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)}},455:function(e,t,r){"use strict";var n=r(459),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("&"):""}},456:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(447),r(455)),i=r.n(o);r(133);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"),"."))}},459: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.4f4dfc9f.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{158: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(451)),i=(r(458),r(455),r(450)),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},449: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}},454: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""}}})},455:function(e,t,r){"use strict";r(454);var n=r(0),a=r.n(n),o=r(450);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)}},457:function(e,t,r){"use strict";var n=r(461),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("&"):""}},458:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(449),r(457)),i=r.n(o);r(133);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"),"."))}},461: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/05049f86.2665fa95.js.LICENSE.txt b/05049f86.4f4dfc9f.js.LICENSE.txt similarity index 100% rename from 05049f86.2665fa95.js.LICENSE.txt rename to 05049f86.4f4dfc9f.js.LICENSE.txt diff --git a/0578cd49.3ab0f7f9.js b/0578cd49.1c5b3eec.js similarity index 93% rename from 0578cd49.3ab0f7f9.js rename to 0578cd49.1c5b3eec.js index 6a775c4407..cab4b00332 100644 --- a/0578cd49.3ab0f7f9.js +++ b/0578cd49.1c5b3eec.js @@ -1,2 +1,2 @@ -/*! For license information please see 0578cd49.3ab0f7f9.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 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(449)),i=n(448),c=n(456),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},447: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}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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 0578cd49.1c5b3eec.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 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(451)),i=n(450),c=n(458),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},449: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}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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/0578cd49.3ab0f7f9.js.LICENSE.txt b/0578cd49.1c5b3eec.js.LICENSE.txt similarity index 100% rename from 0578cd49.3ab0f7f9.js.LICENSE.txt rename to 0578cd49.1c5b3eec.js.LICENSE.txt diff --git a/06e8d299.1e7f2e06.js b/06e8d299.46146730.js similarity index 93% rename from 06e8d299.1e7f2e06.js rename to 06e8d299.46146730.js index d7d1d95fa7..75bb603718 100644 --- a/06e8d299.1e7f2e06.js +++ b/06e8d299.46146730.js @@ -1,2 +1,2 @@ -/*! For license information please see 06e8d299.1e7f2e06.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 s})),n.d(t,"metadata",(function(){return l})),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(449)),c=n(456),i=(n(448),n(453)),s=(n(457),{last_modified_on:"2024-01-05",$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","installation_guide: 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 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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/installation-guide/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. You can retrieve the Kubeconfig of your cluster directly from the Qovery interface by following the procedure "Get your cluster kubeconfig file" ',Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#performing-actions-on-your-clusters"}),"within this section"),".")),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},447: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 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)}},m=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,l=s(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},l,{components:n})):r.a.createElement(d,i({ref:t},l))}));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 s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:o,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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var o=n(0),r=n.n(o),a=n(448);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)}},454:function(e,t,n){"use strict";var o=n(1),r=n(0),a=n.n(r),c=n(39),i=n(458),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),m=l.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}))}},455:function(e,t,n){"use strict";var o=n(459),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("&"):""}},456:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(447),n(455)),c=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.headingDepth,a=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(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: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"),"."))}},457:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=n(454),c=n(447),i=n.n(c);n(134);t.a=function(e){var t=e.children,n=e.className,o=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),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-"+(s||"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)}},458:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},459: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.46146730.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 s})),n.d(t,"metadata",(function(){return l})),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(451)),c=n(458),i=(n(450),n(455)),s=(n(459),{last_modified_on:"2024-01-05",$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","installation_guide: 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 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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/installation-guide/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. You can retrieve the Kubeconfig of your cluster directly from the Qovery interface by following the procedure "Get your cluster kubeconfig file" ',Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#performing-actions-on-your-clusters"}),"within this section"),".")),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},449: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 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)}},m=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,l=s(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},l,{components:n})):r.a.createElement(d,i({ref:t},l))}));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 s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:o,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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var o=n(0),r=n.n(o),a=n(450);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)}},456:function(e,t,n){"use strict";var o=n(1),r=n(0),a=n.n(r),c=n(39),i=n(460),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),m=l.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}))}},457:function(e,t,n){"use strict";var o=n(461),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("&"):""}},458:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(449),n(457)),c=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.headingDepth,a=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(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: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"),"."))}},459:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=n(456),c=n(449),i=n.n(c);n(134);t.a=function(e){var t=e.children,n=e.className,o=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),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-"+(s||"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)}},460:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},461: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.1e7f2e06.js.LICENSE.txt b/06e8d299.46146730.js.LICENSE.txt similarity index 100% rename from 06e8d299.1e7f2e06.js.LICENSE.txt rename to 06e8d299.46146730.js.LICENSE.txt diff --git a/072d4c63.f95bc21a.js b/072d4c63.5598f6c3.js similarity index 93% rename from 072d4c63.f95bc21a.js rename to 072d4c63.5598f6c3.js index 28aa47084a..79670d5aa9 100644 --- a/072d4c63.f95bc21a.js +++ b/072d4c63.5598f6c3.js @@ -1,2 +1,2 @@ -/*! For license information please see 072d4c63.f95bc21a.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{161: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(449)),o=(t(448),t(453),t(457),{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},447: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}},452: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""}}})},453:function(e,n,t){"use strict";t(452);var a=t(0),r=t.n(a),i=t(448);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)}},454:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),c=t(458),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}))}},457:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(454),o=t(447),c=t.n(o);t(134);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)}},458: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.5598f6c3.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{161: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(451)),o=(t(450),t(455),t(459),{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},449: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}},454: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""}}})},455:function(e,n,t){"use strict";t(454);var a=t(0),r=t.n(a),i=t(450);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)}},456:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),c=t(460),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}))}},459:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(456),o=t(449),c=t.n(o);t(134);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)}},460: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/072d4c63.f95bc21a.js.LICENSE.txt b/072d4c63.5598f6c3.js.LICENSE.txt similarity index 100% rename from 072d4c63.f95bc21a.js.LICENSE.txt rename to 072d4c63.5598f6c3.js.LICENSE.txt diff --git a/073aa0b0.2703c244.js b/073aa0b0.91ba0df4.js similarity index 92% rename from 073aa0b0.2703c244.js rename to 073aa0b0.91ba0df4.js index 0494835509..9aa9fc5672 100644 --- a/073aa0b0.2703c244.js +++ b/073aa0b0.91ba0df4.js @@ -1,2 +1,2 @@ -/*! For license information please see 073aa0b0.2703c244.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 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(449)),a=(n(457),n(448)),c=(n(453),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var i=n(0),r=n.n(i),o=n(448);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)}},454:function(e,t,n){"use strict";var i=n(1),r=n(0),o=n.n(r),a=n(39),c=n(458),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}))}},457:function(e,t,n){"use strict";var i=n(0),r=n.n(i),o=n(454),a=n(447),c=n.n(a);n(134);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)}},458: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.91ba0df4.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 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(451)),a=(n(459),n(450)),c=(n(455),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var i=n(0),r=n.n(i),o=n(450);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)}},456:function(e,t,n){"use strict";var i=n(1),r=n(0),o=n.n(r),a=n(39),c=n(460),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}))}},459:function(e,t,n){"use strict";var i=n(0),r=n.n(i),o=n(456),a=n(449),c=n.n(a);n(134);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)}},460: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/073aa0b0.2703c244.js.LICENSE.txt b/073aa0b0.91ba0df4.js.LICENSE.txt similarity index 100% rename from 073aa0b0.2703c244.js.LICENSE.txt rename to 073aa0b0.91ba0df4.js.LICENSE.txt diff --git a/07c2f310.c82f6ed3.js b/07c2f310.c6541619.js similarity index 98% rename from 07c2f310.c82f6ed3.js rename to 07c2f310.c6541619.js index 217853aef4..0035b62337 100644 --- a/07c2f310.c82f6ed3.js +++ b/07c2f310.c6541619.js @@ -1,2 +1,2 @@ -/*! For license information please see 07c2f310.c82f6ed3.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{163: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(449)),l=a(448),b=a(456),o={last_modified_on:"2024-05-22",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"},"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)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,'The "Variables tab" is available on the Environment list and Service list screens as well but it will let you manage only the environment variables with Scope = Project or Environment.'))),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)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"You can bulk delete a set of environment variables by selecting them via the checkbox next to their name")),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},447: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}},455:function(e,t,a){"use strict";var n=a(459),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("&"):""}},456:function(e,t,a){"use strict";var n=a(0),r=a.n(n),i=(a(447),a(455)),l=a.n(i);a(133);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"),"."))}},459: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.c6541619.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{163: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(451)),l=a(450),b=a(458),o={last_modified_on:"2024-05-22",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"},"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)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,'The "Variables tab" is available on the Environment list and Service list screens as well but it will let you manage only the environment variables with Scope = Project or Environment.'))),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)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"You can bulk delete a set of environment variables by selecting them via the checkbox next to their name")),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},449: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}},457:function(e,t,a){"use strict";var n=a(461),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("&"):""}},458:function(e,t,a){"use strict";var n=a(0),r=a.n(n),i=(a(449),a(457)),l=a.n(i);a(133);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"),"."))}},461: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/07c2f310.c82f6ed3.js.LICENSE.txt b/07c2f310.c6541619.js.LICENSE.txt similarity index 100% rename from 07c2f310.c82f6ed3.js.LICENSE.txt rename to 07c2f310.c6541619.js.LICENSE.txt diff --git a/099598c5.cc13ff49.js b/099598c5.fb01dc21.js similarity index 91% rename from 099598c5.cc13ff49.js rename to 099598c5.fb01dc21.js index d5f8d59744..723565a14c 100644 --- a/099598c5.cc13ff49.js +++ b/099598c5.fb01dc21.js @@ -1,2 +1,2 @@ -/*! For license information please see 099598c5.cc13ff49.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{164: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 d}));var r=n(1),a=n(9),o=(n(0),n(449)),c=n(456),i=(n(448),n(453)),l={last_modified_on:"2023-12-30",title:"Quickstart",description:"Learn how to quickly install Qovery on your Amazon Web Services (AWS) account"},s={id:"getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart",title:"Quickstart",description:"Learn how to quickly install Qovery on your Amazon Web Services (AWS) account",source:"@site/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart.md",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart",sidebar:"docs",previous:{title:"Managed By Qovery",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery"},next:{title:"Create Credentials",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials"}},u=[{value:"Create a Kubernetes cluster",id:"create-a-kubernetes-cluster",children:[]},{value:"Attach AWS credentials",id:"attach-aws-credentials",children:[]},{value:"Select your options",id:"select-your-options",children:[]},{value:"Install Qovery",id:"install-qovery",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,"Install Qovery on your AWS account in less than 30 minutes. Qovery will create a Kubernetes cluster for you and manage it for you. To install Qovery on an existing Kubernetes cluster, please refer to the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/"}),"dedicated documentation"),"."),Object(o.b)(i.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have an account and an ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/"}),"Organization")," on Qovery"),Object(o.b)("li",{parentName:"ul"},"You have an AWS account"))),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h2",{id:"create-a-kubernetes-cluster"},"Create a Kubernetes cluster"),Object(o.b)("p",null,"Now you can create your Kubernetes cluster. Follow this ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"guide")," to create your Kubernetes cluster."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/install-qovery/common/add-cluster.jpg",alt:"Add Cluster"})),Object(o.b)("p",null,"Note that you can create multiple clusters on the same AWS account with different VPCs. You can also create multiple clusters on different AWS accounts. Qovery will manage them for you.")),Object(o.b)("li",null,Object(o.b)("h2",{id:"attach-aws-credentials"},"Attach AWS credentials"),Object(o.b)("p",null,"Follow this ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials/"}),"guide")," to create your AWS credentials."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/install-qovery/aws/create-credentials.jpg",alt:"Create Credentials"})),Object(o.b)("p",null,"Then attach your credentials to your cluster and click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create"),". Then, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Continue"),".")),Object(o.b)("li",null,Object(o.b)("h2",{id:"select-your-options"},"Select your options"),Object(o.b)("p",null,"Qovery propose multiple options that you can select to customize your installation. You can also change some of them later.")),Object(o.b)("li",null,Object(o.b)("h2",{id:"install-qovery"},"Install Qovery"),Object(o.b)("p",null,"Click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create and Deploy")," to create the cluster and install Qovery on it."),Object(o.b)("p",null,"It will take up to 30 minutes to create the cluster, VPC and install Qovery on it. But you can already ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"configure your first application"),"."),Object(o.b)("p",null,"You should see your new cluster in the list of clusters."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/install-qovery/common/list-clusters.jpg",alt:"Show clusters"}))))))}d.isMDXComponent=!0},447: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},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,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),b=r,f=p["".concat(c,".").concat(b)]||p[b]||d[b]||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]=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 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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),c=n.n(o);n(133);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),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"),"."))}},459: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 099598c5.fb01dc21.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{164: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 d}));var r=n(1),a=n(9),o=(n(0),n(451)),c=n(458),i=(n(450),n(455)),l={last_modified_on:"2023-12-30",title:"Quickstart",description:"Learn how to quickly install Qovery on your Amazon Web Services (AWS) account"},s={id:"getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart",title:"Quickstart",description:"Learn how to quickly install Qovery on your Amazon Web Services (AWS) account",source:"@site/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart.md",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart",sidebar:"docs",previous:{title:"Managed By Qovery",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery"},next:{title:"Create Credentials",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials"}},u=[{value:"Create a Kubernetes cluster",id:"create-a-kubernetes-cluster",children:[]},{value:"Attach AWS credentials",id:"attach-aws-credentials",children:[]},{value:"Select your options",id:"select-your-options",children:[]},{value:"Install Qovery",id:"install-qovery",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,"Install Qovery on your AWS account in less than 30 minutes. Qovery will create a Kubernetes cluster for you and manage it for you. To install Qovery on an existing Kubernetes cluster, please refer to the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/"}),"dedicated documentation"),"."),Object(o.b)(i.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have an account and an ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/"}),"Organization")," on Qovery"),Object(o.b)("li",{parentName:"ul"},"You have an AWS account"))),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h2",{id:"create-a-kubernetes-cluster"},"Create a Kubernetes cluster"),Object(o.b)("p",null,"Now you can create your Kubernetes cluster. Follow this ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"guide")," to create your Kubernetes cluster."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/install-qovery/common/add-cluster.jpg",alt:"Add Cluster"})),Object(o.b)("p",null,"Note that you can create multiple clusters on the same AWS account with different VPCs. You can also create multiple clusters on different AWS accounts. Qovery will manage them for you.")),Object(o.b)("li",null,Object(o.b)("h2",{id:"attach-aws-credentials"},"Attach AWS credentials"),Object(o.b)("p",null,"Follow this ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials/"}),"guide")," to create your AWS credentials."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/install-qovery/aws/create-credentials.jpg",alt:"Create Credentials"})),Object(o.b)("p",null,"Then attach your credentials to your cluster and click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create"),". Then, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Continue"),".")),Object(o.b)("li",null,Object(o.b)("h2",{id:"select-your-options"},"Select your options"),Object(o.b)("p",null,"Qovery propose multiple options that you can select to customize your installation. You can also change some of them later.")),Object(o.b)("li",null,Object(o.b)("h2",{id:"install-qovery"},"Install Qovery"),Object(o.b)("p",null,"Click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create and Deploy")," to create the cluster and install Qovery on it."),Object(o.b)("p",null,"It will take up to 30 minutes to create the cluster, VPC and install Qovery on it. But you can already ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"configure your first application"),"."),Object(o.b)("p",null,"You should see your new cluster in the list of clusters."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/install-qovery/common/list-clusters.jpg",alt:"Show clusters"}))))))}d.isMDXComponent=!0},449: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},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,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),b=r,f=p["".concat(c,".").concat(b)]||p[b]||d[b]||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]=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 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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),c=n.n(o);n(133);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),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"),"."))}},461: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/099598c5.cc13ff49.js.LICENSE.txt b/099598c5.fb01dc21.js.LICENSE.txt similarity index 100% rename from 099598c5.cc13ff49.js.LICENSE.txt rename to 099598c5.fb01dc21.js.LICENSE.txt diff --git a/0c18cf89.661d3128.js b/0c18cf89.518a98d9.js similarity index 90% rename from 0c18cf89.661d3128.js rename to 0c18cf89.518a98d9.js index fb29e6285d..fb62dbeddb 100644 --- a/0c18cf89.661d3128.js +++ b/0c18cf89.518a98d9.js @@ -1,2 +1,2 @@ -/*! For license information please see 0c18cf89.661d3128.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{165: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 c})),r.d(t,"default",(function(){return p}));var n=r(1),o=r(9),a=(r(0),r(449)),i=r(448),l={last_modified_on:"2023-12-30",$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","installation_guide: aws"],hide_pagination:!0},u={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:"1 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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"}},c=[],s={rightToc:c};function p(e){var t=e.components,r=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Access our new installation guide of Qovery on AWS ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/"}),"here"))))}p.isMDXComponent=!0},447: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 c=o.a.createContext({}),s=function(e){var t=o.a.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l({},t,{},e)),r},p=function(e){var t=s(e.components);return o.a.createElement(c.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,c=u(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,y=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return r?o.a.createElement(y,l({ref:t},c,{components:r})):o.a.createElement(y,l({ref:t},c))}));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]=d;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l.mdxType="string"==typeof e?e:n,i[1]=l;for(var c=2;c1?arguments[1]:void 0,r),u=i>2?arguments[2]:void 0,c=void 0===u?r:o(u,r);c>l;)t[l++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see 0c18cf89.518a98d9.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{165: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 c})),r.d(t,"default",(function(){return p}));var n=r(1),o=r(9),a=(r(0),r(451)),i=r(450),l={last_modified_on:"2023-12-30",$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","installation_guide: aws"],hide_pagination:!0},u={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:"1 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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"}},c=[],s={rightToc:c};function p(e){var t=e.components,r=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Access our new installation guide of Qovery on AWS ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/"}),"here"))))}p.isMDXComponent=!0},449: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 c=o.a.createContext({}),s=function(e){var t=o.a.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l({},t,{},e)),r},p=function(e){var t=s(e.components);return o.a.createElement(c.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,c=u(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,y=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return r?o.a.createElement(y,l({ref:t},c,{components:r})):o.a.createElement(y,l({ref:t},c))}));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]=d;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l.mdxType="string"==typeof e?e:n,i[1]=l;for(var c=2;c1?arguments[1]:void 0,r),u=i>2?arguments[2]:void 0,c=void 0===u?r:o(u,r);c>l;)t[l++]=e;return t}}}]); \ No newline at end of file diff --git a/0c18cf89.661d3128.js.LICENSE.txt b/0c18cf89.518a98d9.js.LICENSE.txt similarity index 100% rename from 0c18cf89.661d3128.js.LICENSE.txt rename to 0c18cf89.518a98d9.js.LICENSE.txt diff --git a/0f632e24.886cf6f3.js b/0f632e24.111042af.js similarity index 90% rename from 0f632e24.886cf6f3.js rename to 0f632e24.111042af.js index 5bcdfe04fd..0b9bbf0ed9 100644 --- a/0f632e24.886cf6f3.js +++ b/0f632e24.111042af.js @@ -1,2 +1,2 @@ -/*! For license information please see 0f632e24.886cf6f3.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 i})),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(449)),c=r(457),i={last_modified_on:"2023-12-30",title:"Managed By Qovery",sidebar_label:"hidden",hide_pagination:!0},u={id:"getting-started/install-qovery/azure/cluster-managed-by-qovery",title:"Managed By Qovery",description:"import Jump from '@site/src/components/Jump';",source:"@site/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery.md",permalink:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Azure",permalink:"/docs/getting-started/install-qovery/azure"},next:{title:"Quickstart",permalink:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart"}},s=[],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,"Don't be shy, pick the first page you want to read and start your journey with Qovery."),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart",mdxType:"Jump"},"Quickstart"))}p.isMDXComponent=!0},447: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):i({},t,{},e)),r},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(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(r),d=n,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||o;return r?a.a.createElement(m,i({ref:t},s,{components:r})):a.a.createElement(m,i({ref:t},s))}));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]=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:n,c[1]=i;for(var s=2;s0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):o.a.createElement("a",Object(n.a)({},e,{href:l}))}},457:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(454),c=r(447),i=r.n(c);r(134);t.a=function(e){var t=e.children,r=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,r),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"},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-"+(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)}},458: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 0f632e24.111042af.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 i})),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(451)),c=r(459),i={last_modified_on:"2023-12-30",title:"Managed By Qovery",sidebar_label:"hidden",hide_pagination:!0},u={id:"getting-started/install-qovery/azure/cluster-managed-by-qovery",title:"Managed By Qovery",description:"import Jump from '@site/src/components/Jump';",source:"@site/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery.md",permalink:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Azure",permalink:"/docs/getting-started/install-qovery/azure"},next:{title:"Quickstart",permalink:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart"}},s=[],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,"Don't be shy, pick the first page you want to read and start your journey with Qovery."),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart",mdxType:"Jump"},"Quickstart"))}p.isMDXComponent=!0},449: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):i({},t,{},e)),r},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(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),p=l(r),d=n,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||o;return r?a.a.createElement(m,i({ref:t},s,{components:r})):a.a.createElement(m,i({ref:t},s))}));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]=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:n,c[1]=i;for(var s=2;s0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):o.a.createElement("a",Object(n.a)({},e,{href:l}))}},459:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(456),c=r(449),i=r.n(c);r(134);t.a=function(e){var t=e.children,r=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,r),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"},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-"+(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)}},460: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/0f632e24.886cf6f3.js.LICENSE.txt b/0f632e24.111042af.js.LICENSE.txt similarity index 100% rename from 0f632e24.886cf6f3.js.LICENSE.txt rename to 0f632e24.111042af.js.LICENSE.txt diff --git a/1.32f1d213.js b/1.73d12a43.js similarity index 98% rename from 1.32f1d213.js rename to 1.73d12a43.js index f291bfd775..0d6f9ea91e 100644 --- a/1.32f1d213.js +++ b/1.73d12a43.js @@ -1,2 +1,2 @@ -/*! For license information please see 1.32f1d213.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[1],{447: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}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},459:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}},462:function(e,t,n){"use strict";var r=n(12),o=n(489)(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")},465:function(e,t,n){"use strict";var r=n(8),o=n(510),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}]}))},468:function(e,t,n){"use strict";var r=n(0),o=n(478);t.a=function(){return Object(r.useContext)(o.a)}},469: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},478:function(e,t,n){"use strict";var r=n(0),o=Object(r.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=o},489:function(e,t,n){var r=n(30),o=n(54),i=n(27),u=n(26),a=n(490);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}}},490:function(e,t,n){var r=n(491);e.exports=function(e,t){return new(r(e))(t)}},491:function(e,t,n){var r=n(13),o=n(492),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}},492:function(e,t,n){var r=n(23);e.exports=Array.isArray||function(e){return"Array"==r(e)}},510:function(e,t){e.exports=Object.is||function(e,t){return e===t?0!==e||1/e==1/t:e!=e&&t!=t}},590: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.73d12a43.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[1],{449: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}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},461:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}},464:function(e,t,n){"use strict";var r=n(12),o=n(491)(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")},467:function(e,t,n){"use strict";var r=n(8),o=n(512),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}]}))},470:function(e,t,n){"use strict";var r=n(0),o=n(480);t.a=function(){return Object(r.useContext)(o.a)}},471: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},480:function(e,t,n){"use strict";var r=n(0),o=Object(r.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=o},491:function(e,t,n){var r=n(30),o=n(54),i=n(27),u=n(26),a=n(492);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}}},492:function(e,t,n){var r=n(493);e.exports=function(e,t){return new(r(e))(t)}},493:function(e,t,n){var r=n(13),o=n(494),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}},494:function(e,t,n){var r=n(23);e.exports=Array.isArray||function(e){return"Array"==r(e)}},512:function(e,t){e.exports=Object.is||function(e,t){return e===t?0!==e||1/e==1/t:e!=e&&t!=t}},592: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/1.32f1d213.js.LICENSE.txt b/1.73d12a43.js.LICENSE.txt similarity index 100% rename from 1.32f1d213.js.LICENSE.txt rename to 1.73d12a43.js.LICENSE.txt diff --git a/10c2e3e6.f9472441.js b/10c2e3e6.0b57a23c.js similarity index 91% rename from 10c2e3e6.f9472441.js rename to 10c2e3e6.0b57a23c.js index ae40b2daa7..f506fa18ab 100644 --- a/10c2e3e6.f9472441.js +++ b/10c2e3e6.0b57a23c.js @@ -1,2 +1,2 @@ -/*! For license information please see 10c2e3e6.f9472441.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),a=r(9),o=(r(0),r(449)),i=(r(456),r(453),r(448)),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:"Monitor and reduce Kubernetes spend with Kubecost",permalink:"/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost"}},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},447: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}},452: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""}}})},453:function(e,t,r){"use strict";r(452);var n=r(0),a=r.n(n),o=r(448);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)}},455:function(e,t,r){"use strict";var n=r(459),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("&"):""}},456:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(447),r(455)),i=r.n(o);r(133);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"),"."))}},459: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.0b57a23c.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),a=r(9),o=(r(0),r(451)),i=(r(458),r(455),r(450)),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:"Monitor and reduce Kubernetes spend with Kubecost",permalink:"/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost"}},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},449: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}},454: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""}}})},455:function(e,t,r){"use strict";r(454);var n=r(0),a=r.n(n),o=r(450);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)}},457:function(e,t,r){"use strict";var n=r(461),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("&"):""}},458:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(449),r(457)),i=r.n(o);r(133);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"),"."))}},461: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/10c2e3e6.f9472441.js.LICENSE.txt b/10c2e3e6.0b57a23c.js.LICENSE.txt similarity index 100% rename from 10c2e3e6.f9472441.js.LICENSE.txt rename to 10c2e3e6.0b57a23c.js.LICENSE.txt diff --git a/10dee872.e845ec61.js b/10dee872.62eeca7d.js similarity index 96% rename from 10dee872.e845ec61.js rename to 10dee872.62eeca7d.js index eaf3ff0708..9c7f9e2945 100644 --- a/10dee872.e845ec61.js +++ b/10dee872.62eeca7d.js @@ -1,2 +1,2 @@ -/*! For license information please see 10dee872.e845ec61.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{169: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(449)),i=(a(448),a(453),a(457)),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},447: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}},452: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""}}})},453:function(e,t,a){"use strict";a(452);var r=a(0),n=a.n(r),o=a(448);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)}},454:function(e,t,a){"use strict";var r=a(1),n=a(0),o=a.n(n),i=a(39),c=a(458),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}))}},457:function(e,t,a){"use strict";var r=a(0),n=a.n(r),o=a(454),i=a(447),c=a.n(i);a(134);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)}},458: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.62eeca7d.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{169: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(451)),i=(a(450),a(455),a(459)),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},449: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}},454: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""}}})},455:function(e,t,a){"use strict";a(454);var r=a(0),n=a.n(r),o=a(450);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)}},456:function(e,t,a){"use strict";var r=a(1),n=a(0),o=a.n(n),i=a(39),c=a(460),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}))}},459:function(e,t,a){"use strict";var r=a(0),n=a.n(r),o=a(456),i=a(449),c=a.n(i);a(134);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)}},460: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/10dee872.e845ec61.js.LICENSE.txt b/10dee872.62eeca7d.js.LICENSE.txt similarity index 100% rename from 10dee872.e845ec61.js.LICENSE.txt rename to 10dee872.62eeca7d.js.LICENSE.txt diff --git a/115eba8e.5f8665a4.js b/115eba8e.3d9eef15.js similarity index 90% rename from 115eba8e.5f8665a4.js rename to 115eba8e.3d9eef15.js index 9d3e2dac77..4a383973c7 100644 --- a/115eba8e.5f8665a4.js +++ b/115eba8e.3d9eef15.js @@ -1,2 +1,2 @@ -/*! For license information please see 115eba8e.5f8665a4.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{170:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return s})),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(449)),c=r(457),i={last_modified_on:"2023-12-30",title:"Azure",sidebar_label:"hidden",hide_pagination:!0},s={id:"getting-started/install-qovery/azure",title:"Azure",description:"import Jump from '@site/src/components/Jump';",source:"@site/docs/getting-started/install-qovery/azure.md",permalink:"/docs/getting-started/install-qovery/azure",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Self-Managed Cluster",permalink:"/docs/getting-started/install-qovery/scaleway/self-managed-cluster"},next:{title:"Managed By Qovery",permalink:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery"}},u=[],l={rightToc:u};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,"It's a good choice. Choose your path:"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery",mdxType:"Jump"},"Cluster Managed by Qovery"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/azure/self-managed-cluster",mdxType:"Jump"},"Self-Managed Cluster"))}p.isMDXComponent=!0},447: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({}),l=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=l(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)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),d=n,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||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]=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:n,c[1]=i;for(var u=2;u0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):o.a.createElement("a",Object(n.a)({},e,{href:l}))}},457:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(454),c=r(447),i=r.n(c);r(134);t.a=function(e){var t=e.children,r=e.className,n=e.badge,c=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,f=i()("jump-to","jump-to--"+u,r),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"},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 l?a.a.createElement("a",{href:p,target:l,className:f},d):a.a.createElement(o.a,{to:p,className:f},d)}},458: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 115eba8e.3d9eef15.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{170:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return s})),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(451)),c=r(459),i={last_modified_on:"2023-12-30",title:"Azure",sidebar_label:"hidden",hide_pagination:!0},s={id:"getting-started/install-qovery/azure",title:"Azure",description:"import Jump from '@site/src/components/Jump';",source:"@site/docs/getting-started/install-qovery/azure.md",permalink:"/docs/getting-started/install-qovery/azure",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Self-Managed Cluster",permalink:"/docs/getting-started/install-qovery/scaleway/self-managed-cluster"},next:{title:"Managed By Qovery",permalink:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery"}},u=[],l={rightToc:u};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,"It's a good choice. Choose your path:"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery",mdxType:"Jump"},"Cluster Managed by Qovery"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/azure/self-managed-cluster",mdxType:"Jump"},"Self-Managed Cluster"))}p.isMDXComponent=!0},449: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({}),l=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=l(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)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),d=n,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||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]=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:n,c[1]=i;for(var u=2;u0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):o.a.createElement("a",Object(n.a)({},e,{href:l}))}},459:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(456),c=r(449),i=r.n(c);r(134);t.a=function(e){var t=e.children,r=e.className,n=e.badge,c=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,f=i()("jump-to","jump-to--"+u,r),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"},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 l?a.a.createElement("a",{href:p,target:l,className:f},d):a.a.createElement(o.a,{to:p,className:f},d)}},460: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/115eba8e.5f8665a4.js.LICENSE.txt b/115eba8e.3d9eef15.js.LICENSE.txt similarity index 100% rename from 115eba8e.5f8665a4.js.LICENSE.txt rename to 115eba8e.3d9eef15.js.LICENSE.txt diff --git a/120e882c.7015c77f.js b/120e882c.22c57be3.js similarity index 95% rename from 120e882c.7015c77f.js rename to 120e882c.22c57be3.js index b0b622f6bc..6e7e8dfe15 100644 --- a/120e882c.7015c77f.js +++ b/120e882c.22c57be3.js @@ -1,2 +1,2 @@ -/*! For license information please see 120e882c.7015c77f.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{171: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(449)),i=t(448),c=t(453),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},447: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}},452: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""}}})},453:function(e,n,t){"use strict";t(452);var o=t(0),r=t.n(o),a=t(448);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.22c57be3.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{171: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(451)),i=t(450),c=t(455),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},449: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}},454: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""}}})},455:function(e,n,t){"use strict";t(454);var o=t(0),r=t.n(o),a=t(450);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/120e882c.7015c77f.js.LICENSE.txt b/120e882c.22c57be3.js.LICENSE.txt similarity index 100% rename from 120e882c.7015c77f.js.LICENSE.txt rename to 120e882c.22c57be3.js.LICENSE.txt diff --git a/1350cb71.cb6737d2.js b/1350cb71.d804cd3e.js similarity index 96% rename from 1350cb71.cb6737d2.js rename to 1350cb71.d804cd3e.js index 6752fc4e6a..bd269dfa9f 100644 --- a/1350cb71.cb6737d2.js +++ b/1350cb71.d804cd3e.js @@ -1,2 +1,2 @@ -/*! For license information please see 1350cb71.cb6737d2.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 s})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return d}));var o=n(1),r=n(9),a=(n(0),n(449)),i=n(448),c=n(456),s={last_modified_on:"2023-12-26",title:"Service Deployment Troubleshoot",description:"How to troubleshoot your service deployments with Qovery",hide_pagination:!0},l={id:"using-qovery/troubleshoot/service-deployment-troubleshoot",title:"Service Deployment Troubleshoot",description:"How to troubleshoot your service deployments with Qovery",source:"@site/docs/using-qovery/troubleshoot/service-deployment-troubleshoot.md",permalink:"/docs/using-qovery/troubleshoot/service-deployment-troubleshoot",sidebar:"docs",previous:{title:"Troubleshoot",permalink:"/docs/using-qovery/troubleshoot"},next:{title:"Service Run Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/service-run-troubleshoot"}},u=[{value:"Generic",id:"generic",children:[{value:"Liveness/Readiness failed, connect: connection refused",id:"livenessreadiness-failed-connect-connection-refused",children:[]},{value:"0/x nodes are available: x insufficient cpu/ram",id:"0x-nodes-are-available-x-insufficient-cpuram",children:[]},{value:"My app is crashing during deployment, how do I connect to investigate?",id:"my-app-is-crashing-during-deployment-how-do-i-connect-to-investigate",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:[]}]},{value:"Lifecycle Jobs / Cronjobs",id:"lifecycle-jobs--cronjobs",children:[{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:[]}]},{value:"Database",id:"database",children:[{value:"SnapshotQuotaExceeded - while deleting a managed DB",id:"snapshotquotaexceeded---while-deleting-a-managed-db",children:[]}]}],b={rightToc:u};function d(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,"Within this section you will find the common errors you might encounter when deploying your services with Qovery"),Object(a.b)("h2",{id:"generic"},"Generic"),Object(a.b)("h3",{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)("h3",{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)("h3",{id:"my-app-is-crashing-during-deployment-how-do-i-connect-to-investigate"},"My app is crashing during deployment, 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)("h3",{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)("h3",{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)("h3",{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."),Object(a.b)("h2",{id:"lifecycle-jobs--cronjobs"},"Lifecycle Jobs / Cronjobs"),Object(a.b)("h3",{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(a.b)("p",null,"This errors occurs in the following two cases:"),Object(a.b)("p",null,Object(a.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(a.b)("p",null,Object(a.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(a.b)("inlineCode",{parentName:"p"},"Max Duration")," value within the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/#job-configuration"}),"Lifecycle Job configuration page")),Object(a.b)("h2",{id:"database"},"Database"),Object(a.b)("h3",{id:"snapshotquotaexceeded---while-deleting-a-managed-db"},"SnapshotQuotaExceeded - while deleting a managed DB"),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)(c.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.")))))}d.isMDXComponent=!0},447: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 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},b=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)}},p=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"]),b=u(n),p=o,h=b["".concat(i,".").concat(p)]||b[p]||d[p]||a;return n?r.a.createElement(h,c({ref:t},l,{components:n})):r.a.createElement(h,c({ref:t},l))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);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:o,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}},455:function(e,t,n){"use strict";var o=n(459),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("&"):""}},456:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(447),n(455)),i=n.n(a);n(133);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"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),u=Object(o.useState)(null),b=u[0],d=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 d("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"),"."))}},459: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 1350cb71.d804cd3e.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 s})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return d}));var o=n(1),r=n(9),a=(n(0),n(451)),i=n(450),c=n(458),s={last_modified_on:"2023-12-26",title:"Service Deployment Troubleshoot",description:"How to troubleshoot your service deployments with Qovery",hide_pagination:!0},l={id:"using-qovery/troubleshoot/service-deployment-troubleshoot",title:"Service Deployment Troubleshoot",description:"How to troubleshoot your service deployments with Qovery",source:"@site/docs/using-qovery/troubleshoot/service-deployment-troubleshoot.md",permalink:"/docs/using-qovery/troubleshoot/service-deployment-troubleshoot",sidebar:"docs",previous:{title:"Troubleshoot",permalink:"/docs/using-qovery/troubleshoot"},next:{title:"Service Run Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/service-run-troubleshoot"}},u=[{value:"Generic",id:"generic",children:[{value:"Liveness/Readiness failed, connect: connection refused",id:"livenessreadiness-failed-connect-connection-refused",children:[]},{value:"0/x nodes are available: x insufficient cpu/ram",id:"0x-nodes-are-available-x-insufficient-cpuram",children:[]},{value:"My app is crashing during deployment, how do I connect to investigate?",id:"my-app-is-crashing-during-deployment-how-do-i-connect-to-investigate",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:[]}]},{value:"Lifecycle Jobs / Cronjobs",id:"lifecycle-jobs--cronjobs",children:[{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:[]}]},{value:"Database",id:"database",children:[{value:"SnapshotQuotaExceeded - while deleting a managed DB",id:"snapshotquotaexceeded---while-deleting-a-managed-db",children:[]}]}],b={rightToc:u};function d(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,"Within this section you will find the common errors you might encounter when deploying your services with Qovery"),Object(a.b)("h2",{id:"generic"},"Generic"),Object(a.b)("h3",{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)("h3",{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)("h3",{id:"my-app-is-crashing-during-deployment-how-do-i-connect-to-investigate"},"My app is crashing during deployment, 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)("h3",{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)("h3",{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)("h3",{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."),Object(a.b)("h2",{id:"lifecycle-jobs--cronjobs"},"Lifecycle Jobs / Cronjobs"),Object(a.b)("h3",{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(a.b)("p",null,"This errors occurs in the following two cases:"),Object(a.b)("p",null,Object(a.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(a.b)("p",null,Object(a.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(a.b)("inlineCode",{parentName:"p"},"Max Duration")," value within the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/#job-configuration"}),"Lifecycle Job configuration page")),Object(a.b)("h2",{id:"database"},"Database"),Object(a.b)("h3",{id:"snapshotquotaexceeded---while-deleting-a-managed-db"},"SnapshotQuotaExceeded - while deleting a managed DB"),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)(c.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.")))))}d.isMDXComponent=!0},449: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 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},b=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)}},p=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"]),b=u(n),p=o,h=b["".concat(i,".").concat(p)]||b[p]||d[p]||a;return n?r.a.createElement(h,c({ref:t},l,{components:n})):r.a.createElement(h,c({ref:t},l))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);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:o,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}},457:function(e,t,n){"use strict";var o=n(461),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("&"):""}},458:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(449),n(457)),i=n.n(a);n(133);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"},l="https://github.com/qovery/documentation/issues/new?"+i.a.stringify(s),u=Object(o.useState)(null),b=u[0],d=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 d("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"),"."))}},461: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/1350cb71.cb6737d2.js.LICENSE.txt b/1350cb71.d804cd3e.js.LICENSE.txt similarity index 100% rename from 1350cb71.cb6737d2.js.LICENSE.txt rename to 1350cb71.d804cd3e.js.LICENSE.txt diff --git a/150479d1.37e5bd1d.js b/150479d1.4b489518.js similarity index 91% rename from 150479d1.37e5bd1d.js rename to 150479d1.4b489518.js index cdfffc9cdb..bea9a72a6b 100644 --- a/150479d1.37e5bd1d.js +++ b/150479d1.4b489518.js @@ -1,2 +1,2 @@ -/*! For license information please see 150479d1.37e5bd1d.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 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),a=n(9),o=(n(0),n(449)),c=n(456),i=n(448),l=n(453),u={last_modified_on:"2024-01-16",title:"Quickstart",description:"Learn how to quickly install Qovery on your Google Cloud Platform (GCP) account"},s={id:"getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart",title:"Quickstart",description:"Learn how to quickly install Qovery on your Google Cloud Platform (GCP) account",source:"@site/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart.md",permalink:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart",sidebar:"docs",previous:{title:"Managed By Qovery",permalink:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery"},next:{title:"Create Credentials",permalink:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials"}},p=[{value:"Create a Kubernetes cluster",id:"create-a-kubernetes-cluster",children:[]},{value:"Attach GCP credentials",id:"attach-gcp-credentials",children:[]},{value:"Install Qovery",id:"install-qovery",children:[]}],b={rightToc:p};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Install Qovery on your GCP account in less than 20 minutes. Qovery will create a Kubernetes cluster for you and manage it for you. To install Qovery on an existing Kubernetes cluster, please refer to the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/"}),"dedicated documentation"),"."),Object(o.b)(l.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have an account and an ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/"}),"Organization")," on Qovery"),Object(o.b)("li",{parentName:"ul"},"You have an GCP account"),Object(o.b)("li",{parentName:"ul"},"You have a GCP project with billing activated and linked"))),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h2",{id:"create-a-kubernetes-cluster"},"Create a Kubernetes cluster"),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Before creating your cluster, ensure that you have at least ",Object(o.b)("strong",{parentName:"p"},"4 CPUS")," and ",Object(o.b)("strong",{parentName:"p"},"8 GB of memory")," available in your ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://cloud.google.com/docs/quota"}),"GCP quotas"),"."),Object(o.b)("p",null,"These quotas can be edited by yourself or by contacting GCP support.")),Object(o.b)("p",null,"Now you can create your Kubernetes cluster. Follow this ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"guide")," to create your Kubernetes cluster."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/install-qovery/common/add-cluster.jpg",alt:"Add Cluster"})),Object(o.b)("p",null,"Note that you can create multiple clusters on the same GCP account with different VPCs. You can also create multiple clusters on different GCP accounts. Qovery will manage them for you.")),Object(o.b)("li",null,Object(o.b)("h2",{id:"attach-gcp-credentials"},"Attach GCP credentials"),Object(o.b)("p",null,"Follow this ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials/"}),"guide")," to create your GCP credentials."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/install-qovery/gcp/attach-credentials.png",alt:"Attach Credentials"})),Object(o.b)("p",null,"Then attach your credentials to your cluster and click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create"),". Then, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Continue"),".")),Object(o.b)("li",null,Object(o.b)("h2",{id:"install-qovery"},"Install Qovery"),Object(o.b)("p",null,"Click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create and Deploy")," to create the cluster and install Qovery on it."),Object(o.b)("p",null,"It will take up to 20 minutes to create the cluster, VPC and install Qovery on it. But you can already ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"configure your first application"),"."),Object(o.b)("p",null,"You should see your new cluster in the list of clusters."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/install-qovery/common/list-gcp-clusters.jpg",alt:"Show clusters"}))))))}d.isMDXComponent=!0},447: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)},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,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,f=p["".concat(c,".").concat(d)]||p[d]||b[d]||o;return n?a.a.createElement(f,i({ref:t},u,{components:n})):a.a.createElement(f,i({ref:t},u))}));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]=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: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),c=n.n(o);n(133);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"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(r.useState)(null),p=s[0],b=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 b("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"),"."))}},459: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 150479d1.4b489518.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 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),a=n(9),o=(n(0),n(451)),c=n(458),i=n(450),l=n(455),u={last_modified_on:"2024-01-16",title:"Quickstart",description:"Learn how to quickly install Qovery on your Google Cloud Platform (GCP) account"},s={id:"getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart",title:"Quickstart",description:"Learn how to quickly install Qovery on your Google Cloud Platform (GCP) account",source:"@site/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart.md",permalink:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart",sidebar:"docs",previous:{title:"Managed By Qovery",permalink:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery"},next:{title:"Create Credentials",permalink:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials"}},p=[{value:"Create a Kubernetes cluster",id:"create-a-kubernetes-cluster",children:[]},{value:"Attach GCP credentials",id:"attach-gcp-credentials",children:[]},{value:"Install Qovery",id:"install-qovery",children:[]}],b={rightToc:p};function d(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Install Qovery on your GCP account in less than 20 minutes. Qovery will create a Kubernetes cluster for you and manage it for you. To install Qovery on an existing Kubernetes cluster, please refer to the ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/"}),"dedicated documentation"),"."),Object(o.b)(l.a,{mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have an account and an ",Object(o.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/"}),"Organization")," on Qovery"),Object(o.b)("li",{parentName:"ul"},"You have an GCP account"),Object(o.b)("li",{parentName:"ul"},"You have a GCP project with billing activated and linked"))),Object(o.b)(c.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h2",{id:"create-a-kubernetes-cluster"},"Create a Kubernetes cluster"),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Before creating your cluster, ensure that you have at least ",Object(o.b)("strong",{parentName:"p"},"4 CPUS")," and ",Object(o.b)("strong",{parentName:"p"},"8 GB of memory")," available in your ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://cloud.google.com/docs/quota"}),"GCP quotas"),"."),Object(o.b)("p",null,"These quotas can be edited by yourself or by contacting GCP support.")),Object(o.b)("p",null,"Now you can create your Kubernetes cluster. Follow this ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"guide")," to create your Kubernetes cluster."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/install-qovery/common/add-cluster.jpg",alt:"Add Cluster"})),Object(o.b)("p",null,"Note that you can create multiple clusters on the same GCP account with different VPCs. You can also create multiple clusters on different GCP accounts. Qovery will manage them for you.")),Object(o.b)("li",null,Object(o.b)("h2",{id:"attach-gcp-credentials"},"Attach GCP credentials"),Object(o.b)("p",null,"Follow this ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials/"}),"guide")," to create your GCP credentials."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/install-qovery/gcp/attach-credentials.png",alt:"Attach Credentials"})),Object(o.b)("p",null,"Then attach your credentials to your cluster and click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create"),". Then, click on ",Object(o.b)("inlineCode",{parentName:"p"},"Continue"),".")),Object(o.b)("li",null,Object(o.b)("h2",{id:"install-qovery"},"Install Qovery"),Object(o.b)("p",null,"Click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create and Deploy")," to create the cluster and install Qovery on it."),Object(o.b)("p",null,"It will take up to 20 minutes to create the cluster, VPC and install Qovery on it. But you can already ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"configure your first application"),"."),Object(o.b)("p",null,"You should see your new cluster in the list of clusters."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/install-qovery/common/list-gcp-clusters.jpg",alt:"Show clusters"}))))))}d.isMDXComponent=!0},449: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)},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,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,f=p["".concat(c,".").concat(d)]||p[d]||b[d]||o;return n?a.a.createElement(f,i({ref:t},u,{components:n})):a.a.createElement(f,i({ref:t},u))}));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]=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: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),c=n.n(o);n(133);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"},u="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(l),s=Object(r.useState)(null),p=s[0],b=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 b("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"),"."))}},461: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/150479d1.37e5bd1d.js.LICENSE.txt b/150479d1.4b489518.js.LICENSE.txt similarity index 100% rename from 150479d1.37e5bd1d.js.LICENSE.txt rename to 150479d1.4b489518.js.LICENSE.txt diff --git a/16557ade.6e9665ac.js b/16557ade.35dea29f.js similarity index 96% rename from 16557ade.6e9665ac.js rename to 16557ade.35dea29f.js index 17d69209af..104e393006 100644 --- a/16557ade.6e9665ac.js +++ b/16557ade.35dea29f.js @@ -1,2 +1,2 @@ -/*! For license information please see 16557ade.6e9665ac.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 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(449)),r=n(456),l=(n(457),n(448)),c=n(453),s={last_modified_on:"2024-07-03",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:"Job output",id:"job-output",children:[]},{value:"Force Run",id:"force-run",children:[]},{value:"Configuration",id:"configuration",children:[{value:"General",id:"general",children:[]},{value:"Dockerfile",id:"dockerfile",children:[]},{value:"JOB Configuration",id:"job-configuration",children:[]},{value:"Resources",id:"resources",children:[]},{value:"Deployment Restrictions",id:"deployment-restrictions",children:[]},{value:"Advanced Settings",id:"advanced-settings",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(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). You can add a new git access by clicking on ",Object(i.b)("inlineCode",{parentName:"li"},"New git access"),"."),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)("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.You can add a new container registry by clicking on ",Object(i.b)("inlineCode",{parentName:"li"},"New registry"),"."),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)("p",null,Object(i.b)("strong",{parentName:"p"}," Extra labels/annotations (optional)")),Object(i.b)("p",null,"Add your extra annotation/label groups. See the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/labels-annotations/"}),"Add annotation/label group")," section for more information.")),Object(i.b)("li",null,"Specify the Dockerfile",Object(i.b)("p",null,"See the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"#dockerfile"}),"Dockerfile section")," for more information.")),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 application (not mandatory) separated with a space. Example: ",Object(i.b)("inlineCode",{parentName:"li"},'rails -h 0.0.0.0 -p 8080 string "complex arg"'),"."),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:"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,"The output (and thus the created environment variables) are displayed in the Lifecycle job overview."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/job/job_output.png",alt:"Job output"})),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:"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)("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)("p",null,Object(i.b)("strong",{parentName:"p"}," Extra labels/annotations (optional)")),Object(i.b)("p",null,"Add your extra annotation/label groups. See the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/labels-annotations/"}),"Add annotation/label group")," section for more information."),Object(i.b)("h3",{id:"dockerfile"},"Dockerfile"),Object(i.b)("p",null,'If your job is built via the Qovery CI (Source="Git Repository"), this section allows you to define the Dockerfile location. '),Object(i.b)("p",null,"Two options are available, depending on where you want to store the Dockerfile:"),Object(i.b)("h4",{id:"git-repository-1"},"Git repository"),Object(i.b)("p",null,"Specify the location of your Dockerfile in ",Object(i.b)("inlineCode",{parentName:"p"},"Dockefile path")," field."),Object(i.b)("h4",{id:"raw-dockerfile"},"RAW Dockerfile"),Object(i.b)("p",null,"Qovery can store and inject for you the Dockerfile instead of storing it into your repository."),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Qovery does not apply any versioning on the provided Dockerfile, we strongly suggest to store the Dockerfile within your repository.")),Object(i.b)("p",null,"If you don't have one, you can use the ",Object(i.b)("inlineCode",{parentName:"p"},"docker init")," command to generate one for your application (check the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.docker.com/reference/cli/docker/init/"}),"documentation here"),")."),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 application (not mandatory) separated with a space. Example: ",Object(i.b)("inlineCode",{parentName:"li"},'rails -h 0.0.0.0 -p 8080 string "complex arg"'),"."),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:"deployment-restrictions"},"Deployment Restrictions"),Object(i.b)("p",null,"This section allows to specify which changes on your repository should trigger an auto-deploy (if enabled). To know more about how to configure your Deployment Restrictions, have a look at the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/#filtering-commits-triggering-the-auto-deploy"}),"deployment restrictions section"),"."),Object(i.b)("h3",{id:"advanced-settings"},"Advanced Settings"),Object(i.b)("p",null,"You can further customize the service behaviour via the service advanced settings. Check ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/advanced-settings/"}),"this documentation")," to know more."),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)(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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var o=n(0),a=n.n(o),i=n(448);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)}},454:function(e,t,n){"use strict";var o=n(1),a=n(0),i=n.n(a),r=n(39),l=n(458),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}))}},455:function(e,t,n){"use strict";var o=n(459),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("&"):""}},456:function(e,t,n){"use strict";var o=n(0),a=n.n(o),i=(n(447),n(455)),r=n.n(i);n(133);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"),"."))}},457:function(e,t,n){"use strict";var o=n(0),a=n.n(o),i=n(454),r=n(447),l=n.n(r);n(134);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)}},458:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},459: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.35dea29f.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 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(451)),r=n(458),l=(n(459),n(450)),c=n(455),s={last_modified_on:"2024-07-03",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:"Job output",id:"job-output",children:[]},{value:"Force Run",id:"force-run",children:[]},{value:"Configuration",id:"configuration",children:[{value:"General",id:"general",children:[]},{value:"Dockerfile",id:"dockerfile",children:[]},{value:"JOB Configuration",id:"job-configuration",children:[]},{value:"Resources",id:"resources",children:[]},{value:"Deployment Restrictions",id:"deployment-restrictions",children:[]},{value:"Advanced Settings",id:"advanced-settings",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(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). You can add a new git access by clicking on ",Object(i.b)("inlineCode",{parentName:"li"},"New git access"),"."),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)("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.You can add a new container registry by clicking on ",Object(i.b)("inlineCode",{parentName:"li"},"New registry"),"."),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)("p",null,Object(i.b)("strong",{parentName:"p"}," Extra labels/annotations (optional)")),Object(i.b)("p",null,"Add your extra annotation/label groups. See the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/labels-annotations/"}),"Add annotation/label group")," section for more information.")),Object(i.b)("li",null,"Specify the Dockerfile",Object(i.b)("p",null,"See the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"#dockerfile"}),"Dockerfile section")," for more information.")),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 application (not mandatory) separated with a space. Example: ",Object(i.b)("inlineCode",{parentName:"li"},'rails -h 0.0.0.0 -p 8080 string "complex arg"'),"."),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:"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,"The output (and thus the created environment variables) are displayed in the Lifecycle job overview."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/configuration/job/job_output.png",alt:"Job output"})),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:"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)("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)("p",null,Object(i.b)("strong",{parentName:"p"}," Extra labels/annotations (optional)")),Object(i.b)("p",null,"Add your extra annotation/label groups. See the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/labels-annotations/"}),"Add annotation/label group")," section for more information."),Object(i.b)("h3",{id:"dockerfile"},"Dockerfile"),Object(i.b)("p",null,'If your job is built via the Qovery CI (Source="Git Repository"), this section allows you to define the Dockerfile location. '),Object(i.b)("p",null,"Two options are available, depending on where you want to store the Dockerfile:"),Object(i.b)("h4",{id:"git-repository-1"},"Git repository"),Object(i.b)("p",null,"Specify the location of your Dockerfile in ",Object(i.b)("inlineCode",{parentName:"p"},"Dockefile path")," field."),Object(i.b)("h4",{id:"raw-dockerfile"},"RAW Dockerfile"),Object(i.b)("p",null,"Qovery can store and inject for you the Dockerfile instead of storing it into your repository."),Object(i.b)(l.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"Qovery does not apply any versioning on the provided Dockerfile, we strongly suggest to store the Dockerfile within your repository.")),Object(i.b)("p",null,"If you don't have one, you can use the ",Object(i.b)("inlineCode",{parentName:"p"},"docker init")," command to generate one for your application (check the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.docker.com/reference/cli/docker/init/"}),"documentation here"),")."),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 application (not mandatory) separated with a space. Example: ",Object(i.b)("inlineCode",{parentName:"li"},'rails -h 0.0.0.0 -p 8080 string "complex arg"'),"."),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:"deployment-restrictions"},"Deployment Restrictions"),Object(i.b)("p",null,"This section allows to specify which changes on your repository should trigger an auto-deploy (if enabled). To know more about how to configure your Deployment Restrictions, have a look at the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/#filtering-commits-triggering-the-auto-deploy"}),"deployment restrictions section"),"."),Object(i.b)("h3",{id:"advanced-settings"},"Advanced Settings"),Object(i.b)("p",null,"You can further customize the service behaviour via the service advanced settings. Check ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/advanced-settings/"}),"this documentation")," to know more."),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)(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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var o=n(0),a=n.n(o),i=n(450);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)}},456:function(e,t,n){"use strict";var o=n(1),a=n(0),i=n.n(a),r=n(39),l=n(460),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}))}},457:function(e,t,n){"use strict";var o=n(461),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("&"):""}},458:function(e,t,n){"use strict";var o=n(0),a=n.n(o),i=(n(449),n(457)),r=n.n(i);n(133);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"),"."))}},459:function(e,t,n){"use strict";var o=n(0),a=n.n(o),i=n(456),r=n(449),l=n.n(r);n(134);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)}},460:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},461: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/16557ade.6e9665ac.js.LICENSE.txt b/16557ade.35dea29f.js.LICENSE.txt similarity index 100% rename from 16557ade.6e9665ac.js.LICENSE.txt rename to 16557ade.35dea29f.js.LICENSE.txt diff --git a/16976906.70605d13.js b/16976906.d4e0344f.js similarity index 93% rename from 16976906.70605d13.js rename to 16976906.d4e0344f.js index fe46257272..626f4d382a 100644 --- a/16976906.70605d13.js +++ b/16976906.d4e0344f.js @@ -1,2 +1,2 @@ -/*! For license information please see 16976906.70605d13.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{175: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(449)),i=(n(456),n(453),n(448),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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.d4e0344f.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{175: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(451)),i=(n(458),n(455),n(450),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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.70605d13.js.LICENSE.txt b/16976906.d4e0344f.js.LICENSE.txt similarity index 100% rename from 16976906.70605d13.js.LICENSE.txt rename to 16976906.d4e0344f.js.LICENSE.txt diff --git a/16c36934.8be5051a.js b/16c36934.d177f007.js similarity index 94% rename from 16c36934.8be5051a.js rename to 16c36934.d177f007.js index b24c5bc15a..0ebae72e9b 100644 --- a/16c36934.8be5051a.js +++ b/16c36934.d177f007.js @@ -1,2 +1,2 @@ -/*! For license information please see 16c36934.8be5051a.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{176: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(449)),a=n(448),c=n(456),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},447: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}},455:function(e,t,n){"use strict";var o=n(459),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("&"):""}},456:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(447),n(455)),a=n.n(i);n(133);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"),"."))}},459: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.d177f007.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{176: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(451)),a=n(450),c=n(458),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},449: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}},457:function(e,t,n){"use strict";var o=n(461),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("&"):""}},458:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(449),n(457)),a=n.n(i);n(133);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"),"."))}},461: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.8be5051a.js.LICENSE.txt b/16c36934.d177f007.js.LICENSE.txt similarity index 100% rename from 16c36934.8be5051a.js.LICENSE.txt rename to 16c36934.d177f007.js.LICENSE.txt diff --git a/1772e35f.9a532a73.js b/1772e35f.cd6fa268.js similarity index 91% rename from 1772e35f.9a532a73.js rename to 1772e35f.cd6fa268.js index cb8a1c778c..cef94c3a66 100644 --- a/1772e35f.9a532a73.js +++ b/1772e35f.cd6fa268.js @@ -1,2 +1,2 @@ -/*! For license information please see 1772e35f.9a532a73.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{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),i=(n(0),n(449)),a=n(457),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},447: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}))}},457:function(e,t,n){"use strict";var r=n(0),o=n.n(r),i=n(454),a=n(447),c=n.n(a);n(134);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)}},458: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.cd6fa268.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{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),i=(n(0),n(451)),a=n(459),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},449: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}))}},459:function(e,t,n){"use strict";var r=n(0),o=n.n(r),i=n(456),a=n(449),c=n.n(a);n(134);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)}},460: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/1772e35f.9a532a73.js.LICENSE.txt b/1772e35f.cd6fa268.js.LICENSE.txt similarity index 100% rename from 1772e35f.9a532a73.js.LICENSE.txt rename to 1772e35f.cd6fa268.js.LICENSE.txt diff --git a/17896441.4b794804.js b/17896441.91a57b7f.js similarity index 94% rename from 17896441.4b794804.js rename to 17896441.91a57b7f.js index 4b1c9094c6..5dc3e789ee 100644 --- a/17896441.4b794804.js +++ b/17896441.91a57b7f.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{178:function(e,t,a){"use strict";a.r(t);a(472),a(473),a(29),a(22),a(21),a(77);var n=a(0),l=a.n(n),s=a(470),r=a(454),c=a(551),i=a(475),o=a.n(i),m=a(447),d=a.n(m),p=a(179),u=a.n(p),E=a(463),g=a(460),v=a(552);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)))))))}},551:function(e,t,a){"use strict";var n=a(0),l=a.n(n),s=a(454),r=a(447),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([[30],{178:function(e,t,a){"use strict";a.r(t);a(474),a(475),a(29),a(22),a(21),a(77);var n=a(0),l=a.n(n),s=a(472),r=a(456),c=a(553),i=a(477),o=a.n(i),m=a(449),d=a.n(m),p=a(179),u=a.n(p),E=a(465),g=a(462),v=a(554);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)))))))}},553:function(e,t,a){"use strict";var n=a(0),l=a.n(n),s=a(456),r=a(449),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.d442765d.js b/18415bef.c664ee62.js similarity index 88% rename from 18415bef.d442765d.js rename to 18415bef.c664ee62.js index 54c010aca1..37f0563169 100644 --- a/18415bef.d442765d.js +++ b/18415bef.c664ee62.js @@ -1,2 +1,2 @@ -/*! For license information please see 18415bef.d442765d.js.LICENSE.txt */ -(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 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(449)),i=(n(456),n(453),n(448)),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:"Monitor and reduce Kubernetes spend with Kubecost",permalink:"/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost"},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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(447),n(455)),i=n.n(a);n(133);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"),"."))}},459: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.c664ee62.js.LICENSE.txt */ +(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 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(451)),i=(n(458),n(455),n(450)),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:"Monitor and reduce Kubernetes spend with Kubecost",permalink:"/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost"},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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(449),n(457)),i=n.n(a);n(133);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"),"."))}},461: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/18415bef.d442765d.js.LICENSE.txt b/18415bef.c664ee62.js.LICENSE.txt similarity index 100% rename from 18415bef.d442765d.js.LICENSE.txt rename to 18415bef.c664ee62.js.LICENSE.txt diff --git a/1a1dfe25.dd1f2ceb.js b/1a1dfe25.4d16f202.js similarity index 94% rename from 1a1dfe25.dd1f2ceb.js rename to 1a1dfe25.4d16f202.js index 46fa07efdd..b0ab9e9097 100644 --- a/1a1dfe25.dd1f2ceb.js +++ b/1a1dfe25.4d16f202.js @@ -1,2 +1,2 @@ -/*! For license information please see 1a1dfe25.dd1f2ceb.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[32],{181:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),a.d(t,"metadata",(function(){return b})),a.d(t,"rightToc",(function(){return s})),a.d(t,"default",(function(){return p}));var n=a(1),r=a(9),l=(a(0),a(449)),c=a(457),o=a(448),i={last_modified_on:"2024-01-02",title:"Install Qovery",description:"How to install Qovery",sidebar_label:"hidden",hide_pagination:!0},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_label:"hidden",sidebar:"docs",previous:{title:"Basic Concepts",permalink:"/docs/getting-started/basic-concepts"},next:{title:"Local",permalink:"/docs/getting-started/install-qovery/local"}},s=[{value:"Managed Cluster by Qovery vs. Self-Managed - What to choose?",id:"managed-cluster-by-qovery-vs-self-managed---what-to-choose",children:[]}],u={rightToc:s};function p(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(l.b)("wrapper",Object(n.a)({},u,a,{components:t,mdxType:"MDXLayout"}),Object(l.b)(o.a,{type:"warning",mdxType:"Alert"},Object(l.b)("p",null,"Read ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"#managed-cluster-by-qovery-vs-self-managed---what-to-choose"}),"this section of the page")," if you are new to Qovery.")),Object(l.b)(c.a,{to:"/docs/getting-started/install-qovery/aws",mdxType:"Jump"},"Amazon Web Services (AWS)"),Object(l.b)(c.a,{to:"/docs/getting-started/install-qovery/gcp",mdxType:"Jump"},"Google Cloud Platform (GCP)"),Object(l.b)(c.a,{to:"/docs/getting-started/install-qovery/scaleway",mdxType:"Jump"},"Scaleway (SCW)"),Object(l.b)(c.a,{to:"/docs/getting-started/install-qovery/azure",mdxType:"Jump"},"Microsoft Azure"),Object(l.b)(c.a,{to:"/docs/getting-started/install-qovery/kubernetes",mdxType:"Jump"},"Kubernetes"),Object(l.b)("hr",null),Object(l.b)("h2",{id:"managed-cluster-by-qovery-vs-self-managed---what-to-choose"},"Managed Cluster by Qovery vs. Self-Managed - What to choose?"),Object(l.b)("p",null,"Qovery offers two distinct approaches to cluster management: ",Object(l.b)("inlineCode",{parentName:"p"},"Cluster Managed by Qovery")," and ",Object(l.b)("inlineCode",{parentName:"p"},"Self-managed Cluster"),".\nChoose ",Object(l.b)("inlineCode",{parentName:"p"},"Cluster 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 ",Object(l.b)("inlineCode",{parentName:"p"},"Self-Managed")," otherwise."),Object(l.b)("p",null,"Here is a table to help you to choose between both:"),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}),"Feature/Aspect"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Cluster Managed by Qovery (recommended)"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Self-Managed Cluster (advanced)"))),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)("strong",{parentName:"td"},"Management")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Fully managed by Qovery"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Self-managed by the organization")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Control")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Limited control over Kubernetes infrastructure"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Full control over Kubernetes setup")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Supported Cloud Service Providers")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"AWS, GCP, Scaleway"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"All")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Customization")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Standard Qovery configuration"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"High customization and configuration freedom")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Expertise Required")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"None"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Requires Kubernetes expertise")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Responsibility")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery is responsible for maintenance"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Organization is responsible for maintenance")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Developer Experience")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Streamlined and simplified"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Streamlined and simplified (no difference)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Setup Complexity")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Just a AWS, GCP or Scaleway account"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Requires infrastructure and Kubernetes knowledge")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Flexibility in Usage")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Standardized to Qovery's environment"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Flexible to meet specific organizational needs")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Ideal Use Case")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Organizations preferring a hands-off approach"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Organizations with specific Kubernetes needs")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Managed Services")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Cf. list below"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"N/A")))),Object(l.b)(o.a,{type:"info",mdxType:"Alert"},Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"Self-Managed Cluster")," is also known as ",Object(l.b)("inlineCode",{parentName:"p"},"Bring Your Own Kubernetes (BYOK)"),".")),Object(l.b)("details",null,Object(l.b)("summary",null,"Managed Services"),Object(l.b)("p",null,"Here is the list of managed services provided by Qovery with the Kubernetes Managed by Qovery approach:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"Vertical Pod Autoscaler"),Object(l.b)("li",{parentName:"ul"},"Cluster Autoscaler"),Object(l.b)("li",{parentName:"ul"},"CoreDNS"),Object(l.b)("li",{parentName:"ul"},"Cert-manager"),Object(l.b)("li",{parentName:"ul"},"Cert-manager Qovery Webhook"),Object(l.b)("li",{parentName:"ul"},"Nginx Ingress"),Object(l.b)("li",{parentName:"ul"},"Metrics Server"),Object(l.b)("li",{parentName:"ul"},"External DNS"),Object(l.b)("li",{parentName:"ul"},"Promtail"),Object(l.b)("li",{parentName:"ul"},"Loki"),Object(l.b)("li",{parentName:"ul"},"AWS",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"AWS EBS Driver"),Object(l.b)("li",{parentName:"ul"},"AWS Kubeproxy"),Object(l.b)("li",{parentName:"ul"},"AWS CNI"),Object(l.b)("li",{parentName:"ul"},"IAM EKS User Mapper"),Object(l.b)("li",{parentName:"ul"},"Karpenter"),Object(l.b)("li",{parentName:"ul"},"AWS Node Term Handler"))))),Object(l.b)("p",null,"A more detailed comparison is available ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.qovery.com/blog/kubernetes-managed-by-qovery-vs-self-managed-byok"}),"on our blog")))}p.isMDXComponent=!0},447: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 b=r.a.createContext({}),s=function(e){var t=r.a.useContext(b),a=t;return e&&(a="function"==typeof e?e(t):o({},t,{},e)),a},u=function(e){var t=s(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(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,l=e.originalType,c=e.parentName,b=i(e,["components","mdxType","originalType","parentName"]),u=s(a),d=n,m=u["".concat(c,".").concat(d)]||u[d]||p[d]||l;return a?r.a.createElement(m,o({ref:t},b,{components:a})):r.a.createElement(m,o({ref:t},b))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var l=a.length,c=new Array(l);c[0]=d;var o={};for(var i in t)hasOwnProperty.call(t,i)&&(o[i]=t[i]);o.originalType=e,o.mdxType="string"==typeof e?e:n,c[1]=o;for(var b=2;b1?arguments[1]:void 0,a),i=c>2?arguments[2]:void 0,b=void 0===i?a:r(i,a);b>o;)t[o++]=e;return t}},454:function(e,t,a){"use strict";var n=a(1),r=a(0),l=a.n(r),c=a(39),o=a(458),i=a(20),b=a.n(i);t.a=function(e){var t,a=e.to,i=e.href,s=a||i,u=Object(o.a)(s),p=Object(r.useRef)(!1),d=b.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(s),function(){d&&t&&t.disconnect()}}),[s,d,u]),s&&u?l.a.createElement(c.b,Object(n.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var a,n;d&&e&&u&&(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})):l.a.createElement("a",Object(n.a)({},e,{href:s}))}},457:function(e,t,a){"use strict";var n=a(0),r=a.n(n),l=a(454),c=a(447),o=a.n(c);a(134);t.a=function(e){var t=e.children,a=e.className,n=e.badge,c=e.leftIcon,i=e.rightIcon,b=e.size,s=e.target,u=e.to,p=o()("jump-to","jump-to--"+b,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:u,target:s,className:p},d):r.a.createElement(l.a,{to:u,className:p},d)}},458: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 1a1dfe25.4d16f202.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[32],{181:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),a.d(t,"metadata",(function(){return b})),a.d(t,"rightToc",(function(){return s})),a.d(t,"default",(function(){return p}));var n=a(1),r=a(9),l=(a(0),a(451)),c=a(459),o=a(450),i={last_modified_on:"2024-01-02",title:"Install Qovery",description:"How to install Qovery",sidebar_label:"hidden",hide_pagination:!0},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_label:"hidden",sidebar:"docs",previous:{title:"Basic Concepts",permalink:"/docs/getting-started/basic-concepts"},next:{title:"Local",permalink:"/docs/getting-started/install-qovery/local"}},s=[{value:"Managed Cluster by Qovery vs. Self-Managed - What to choose?",id:"managed-cluster-by-qovery-vs-self-managed---what-to-choose",children:[]}],u={rightToc:s};function p(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(l.b)("wrapper",Object(n.a)({},u,a,{components:t,mdxType:"MDXLayout"}),Object(l.b)(o.a,{type:"warning",mdxType:"Alert"},Object(l.b)("p",null,"Read ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"#managed-cluster-by-qovery-vs-self-managed---what-to-choose"}),"this section of the page")," if you are new to Qovery.")),Object(l.b)(c.a,{to:"/docs/getting-started/install-qovery/aws",mdxType:"Jump"},"Amazon Web Services (AWS)"),Object(l.b)(c.a,{to:"/docs/getting-started/install-qovery/gcp",mdxType:"Jump"},"Google Cloud Platform (GCP)"),Object(l.b)(c.a,{to:"/docs/getting-started/install-qovery/scaleway",mdxType:"Jump"},"Scaleway (SCW)"),Object(l.b)(c.a,{to:"/docs/getting-started/install-qovery/azure",mdxType:"Jump"},"Microsoft Azure"),Object(l.b)(c.a,{to:"/docs/getting-started/install-qovery/kubernetes",mdxType:"Jump"},"Kubernetes"),Object(l.b)("hr",null),Object(l.b)("h2",{id:"managed-cluster-by-qovery-vs-self-managed---what-to-choose"},"Managed Cluster by Qovery vs. Self-Managed - What to choose?"),Object(l.b)("p",null,"Qovery offers two distinct approaches to cluster management: ",Object(l.b)("inlineCode",{parentName:"p"},"Cluster Managed by Qovery")," and ",Object(l.b)("inlineCode",{parentName:"p"},"Self-managed Cluster"),".\nChoose ",Object(l.b)("inlineCode",{parentName:"p"},"Cluster 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 ",Object(l.b)("inlineCode",{parentName:"p"},"Self-Managed")," otherwise."),Object(l.b)("p",null,"Here is a table to help you to choose between both:"),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}),"Feature/Aspect"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Cluster Managed by Qovery (recommended)"),Object(l.b)("th",Object(n.a)({parentName:"tr"},{align:null}),"Self-Managed Cluster (advanced)"))),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)("strong",{parentName:"td"},"Management")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Fully managed by Qovery"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Self-managed by the organization")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Control")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Limited control over Kubernetes infrastructure"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Full control over Kubernetes setup")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Supported Cloud Service Providers")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"AWS, GCP, Scaleway"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"All")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Customization")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Standard Qovery configuration"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"High customization and configuration freedom")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Expertise Required")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"None"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Requires Kubernetes expertise")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Responsibility")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Qovery is responsible for maintenance"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Organization is responsible for maintenance")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Developer Experience")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Streamlined and simplified"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Streamlined and simplified (no difference)")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Setup Complexity")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Just a AWS, GCP or Scaleway account"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Requires infrastructure and Kubernetes knowledge")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Flexibility in Usage")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Standardized to Qovery's environment"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Flexible to meet specific organizational needs")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Ideal Use Case")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Organizations preferring a hands-off approach"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Organizations with specific Kubernetes needs")),Object(l.b)("tr",{parentName:"tbody"},Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(l.b)("strong",{parentName:"td"},"Managed Services")),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"Cf. list below"),Object(l.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"N/A")))),Object(l.b)(o.a,{type:"info",mdxType:"Alert"},Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"Self-Managed Cluster")," is also known as ",Object(l.b)("inlineCode",{parentName:"p"},"Bring Your Own Kubernetes (BYOK)"),".")),Object(l.b)("details",null,Object(l.b)("summary",null,"Managed Services"),Object(l.b)("p",null,"Here is the list of managed services provided by Qovery with the Kubernetes Managed by Qovery approach:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"Vertical Pod Autoscaler"),Object(l.b)("li",{parentName:"ul"},"Cluster Autoscaler"),Object(l.b)("li",{parentName:"ul"},"CoreDNS"),Object(l.b)("li",{parentName:"ul"},"Cert-manager"),Object(l.b)("li",{parentName:"ul"},"Cert-manager Qovery Webhook"),Object(l.b)("li",{parentName:"ul"},"Nginx Ingress"),Object(l.b)("li",{parentName:"ul"},"Metrics Server"),Object(l.b)("li",{parentName:"ul"},"External DNS"),Object(l.b)("li",{parentName:"ul"},"Promtail"),Object(l.b)("li",{parentName:"ul"},"Loki"),Object(l.b)("li",{parentName:"ul"},"AWS",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"AWS EBS Driver"),Object(l.b)("li",{parentName:"ul"},"AWS Kubeproxy"),Object(l.b)("li",{parentName:"ul"},"AWS CNI"),Object(l.b)("li",{parentName:"ul"},"IAM EKS User Mapper"),Object(l.b)("li",{parentName:"ul"},"Karpenter"),Object(l.b)("li",{parentName:"ul"},"AWS Node Term Handler"))))),Object(l.b)("p",null,"A more detailed comparison is available ",Object(l.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.qovery.com/blog/kubernetes-managed-by-qovery-vs-self-managed-byok"}),"on our blog")))}p.isMDXComponent=!0},449: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 b=r.a.createContext({}),s=function(e){var t=r.a.useContext(b),a=t;return e&&(a="function"==typeof e?e(t):o({},t,{},e)),a},u=function(e){var t=s(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(n.forwardRef)((function(e,t){var a=e.components,n=e.mdxType,l=e.originalType,c=e.parentName,b=i(e,["components","mdxType","originalType","parentName"]),u=s(a),d=n,m=u["".concat(c,".").concat(d)]||u[d]||p[d]||l;return a?r.a.createElement(m,o({ref:t},b,{components:a})):r.a.createElement(m,o({ref:t},b))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var l=a.length,c=new Array(l);c[0]=d;var o={};for(var i in t)hasOwnProperty.call(t,i)&&(o[i]=t[i]);o.originalType=e,o.mdxType="string"==typeof e?e:n,c[1]=o;for(var b=2;b1?arguments[1]:void 0,a),i=c>2?arguments[2]:void 0,b=void 0===i?a:r(i,a);b>o;)t[o++]=e;return t}},456:function(e,t,a){"use strict";var n=a(1),r=a(0),l=a.n(r),c=a(39),o=a(460),i=a(20),b=a.n(i);t.a=function(e){var t,a=e.to,i=e.href,s=a||i,u=Object(o.a)(s),p=Object(r.useRef)(!1),d=b.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(s),function(){d&&t&&t.disconnect()}}),[s,d,u]),s&&u?l.a.createElement(c.b,Object(n.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var a,n;d&&e&&u&&(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})):l.a.createElement("a",Object(n.a)({},e,{href:s}))}},459:function(e,t,a){"use strict";var n=a(0),r=a.n(n),l=a(456),c=a(449),o=a.n(c);a(134);t.a=function(e){var t=e.children,a=e.className,n=e.badge,c=e.leftIcon,i=e.rightIcon,b=e.size,s=e.target,u=e.to,p=o()("jump-to","jump-to--"+b,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:u,target:s,className:p},d):r.a.createElement(l.a,{to:u,className:p},d)}},460: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/1a1dfe25.dd1f2ceb.js.LICENSE.txt b/1a1dfe25.4d16f202.js.LICENSE.txt similarity index 100% rename from 1a1dfe25.dd1f2ceb.js.LICENSE.txt rename to 1a1dfe25.4d16f202.js.LICENSE.txt diff --git a/1a39f24c.190b5aee.js b/1a39f24c.34667779.js similarity index 93% rename from 1a39f24c.190b5aee.js rename to 1a39f24c.34667779.js index 338f43a951..1abb26a1e1 100644 --- a/1a39f24c.190b5aee.js +++ b/1a39f24c.34667779.js @@ -1,2 +1,2 @@ -/*! For license information please see 1a39f24c.190b5aee.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 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(449)),i=(n(456),n(453),n(448),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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.34667779.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 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(451)),i=(n(458),n(455),n(450),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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/1a39f24c.190b5aee.js.LICENSE.txt b/1a39f24c.34667779.js.LICENSE.txt similarity index 100% rename from 1a39f24c.190b5aee.js.LICENSE.txt rename to 1a39f24c.34667779.js.LICENSE.txt diff --git a/1a3e0044.41b11bb7.js b/1a3e0044.b1344710.js similarity index 96% rename from 1a3e0044.41b11bb7.js rename to 1a3e0044.b1344710.js index 610901105b..a3697d089d 100644 --- a/1a3e0044.41b11bb7.js +++ b/1a3e0044.b1344710.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[34],{183: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(449)),o=n(448),l=(n(461),n(453)),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:"GitOps with Qovery",permalink:"/guides/tutorial/gitops-with-qovery"}},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},448:function(e,t,n){"use strict";n(450);var a=n(0),r=n.n(a),i=n(447),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)}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),i=n(448);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)}},461:function(e,t,n){"use strict";var a=n(1),r=(n(465),n(462),n(52),n(29),n(22),n(21),n(0)),i=n.n(r),o=n(469),l=n(447),c=n.n(l),b=n(455),s=n.n(b),u=n(468),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([[34],{183: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(451)),o=n(450),l=(n(463),n(455)),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:"GitOps with Qovery",permalink:"/guides/tutorial/gitops-with-qovery"}},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},450:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),i=n(449),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)}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),i=n(450);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)}},463:function(e,t,n){"use strict";var a=n(1),r=(n(467),n(464),n(52),n(29),n(22),n(21),n(0)),i=n.n(r),o=n(471),l=n(449),c=n.n(l),b=n(457),s=n.n(b),u=n(470),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/1a6d3985.45355650.js b/1a6d3985.1eb4c775.js similarity index 95% rename from 1a6d3985.45355650.js rename to 1a6d3985.1eb4c775.js index 74b11094ee..378c6ef6a8 100644 --- a/1a6d3985.45355650.js +++ b/1a6d3985.1eb4c775.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[35],{184: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(449)),i=n(448),l=(n(461),n(453)),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},448:function(e,t,n){"use strict";n(450);var a=n(0),o=n.n(a),r=n(447),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)}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),o=n.n(a),r=n(448);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)}},461:function(e,t,n){"use strict";var a=n(1),o=(n(465),n(462),n(52),n(29),n(22),n(21),n(0)),r=n.n(o),i=n(469),l=n(447),c=n.n(l),s=n(455),u=n.n(s),b=n(468),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([[35],{184: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(451)),i=n(450),l=(n(463),n(455)),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},450:function(e,t,n){"use strict";n(452);var a=n(0),o=n.n(a),r=n(449),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)}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),o=n.n(a),r=n(450);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)}},463:function(e,t,n){"use strict";var a=n(1),o=(n(467),n(464),n(52),n(29),n(22),n(21),n(0)),r=n.n(o),i=n(471),l=n(449),c=n.n(l),s=n(457),u=n.n(s),b=n(470),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.6e7f1af7.js b/1aa86e56.5b49ea65.js similarity index 96% rename from 1aa86e56.6e7f1af7.js rename to 1aa86e56.5b49ea65.js index ade585d5b7..0fca710a07 100644 --- a/1aa86e56.6e7f1af7.js +++ b/1aa86e56.5b49ea65.js @@ -1,2 +1,2 @@ -/*! For license information please see 1aa86e56.6e7f1af7.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[36],{185: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(449)),i=t(448),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},447: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.5b49ea65.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[36],{185: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(451)),i=t(450),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},449: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/1aa86e56.6e7f1af7.js.LICENSE.txt b/1aa86e56.5b49ea65.js.LICENSE.txt similarity index 100% rename from 1aa86e56.6e7f1af7.js.LICENSE.txt rename to 1aa86e56.5b49ea65.js.LICENSE.txt diff --git a/1b633bfd.977493ae.js b/1b633bfd.c6f89b56.js similarity index 93% rename from 1b633bfd.977493ae.js rename to 1b633bfd.c6f89b56.js index 206746a8d8..d9fdcc080f 100644 --- a/1b633bfd.977493ae.js +++ b/1b633bfd.c6f89b56.js @@ -1,2 +1,2 @@ -/*! For license information please see 1b633bfd.977493ae.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[37],{186: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 o=n(1),r=n(9),a=(n(0),n(449)),c=n(456),i=(n(448),n(453)),s=(n(457),{last_modified_on:"2024-01-05",$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","installation_guide: 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 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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/installation-guide/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. You can retrieve the Kubeconfig of your cluster directly from the Qovery interface by following the procedure "Get your cluster kubeconfig file" ',Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#performing-actions-on-your-clusters"}),"within this section"),".")),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},447: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 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)}},m=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,l=s(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},l,{components:n})):r.a.createElement(d,i({ref:t},l))}));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 s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:o,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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var o=n(0),r=n.n(o),a=n(448);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)}},454:function(e,t,n){"use strict";var o=n(1),r=n(0),a=n.n(r),c=n(39),i=n(458),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),m=l.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}))}},455:function(e,t,n){"use strict";var o=n(459),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("&"):""}},456:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(447),n(455)),c=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.headingDepth,a=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(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: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"),"."))}},457:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=n(454),c=n(447),i=n.n(c);n(134);t.a=function(e){var t=e.children,n=e.className,o=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),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-"+(s||"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)}},458:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},459: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.c6f89b56.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[37],{186: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 o=n(1),r=n(9),a=(n(0),n(451)),c=n(458),i=(n(450),n(455)),s=(n(459),{last_modified_on:"2024-01-05",$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","installation_guide: 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 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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/installation-guide/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. You can retrieve the Kubeconfig of your cluster directly from the Qovery interface by following the procedure "Get your cluster kubeconfig file" ',Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#performing-actions-on-your-clusters"}),"within this section"),".")),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},449: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 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)}},m=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,l=s(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},l,{components:n})):r.a.createElement(d,i({ref:t},l))}));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 s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:o,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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var o=n(0),r=n.n(o),a=n(450);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)}},456:function(e,t,n){"use strict";var o=n(1),r=n(0),a=n.n(r),c=n(39),i=n(460),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),m=l.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}))}},457:function(e,t,n){"use strict";var o=n(461),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("&"):""}},458:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(449),n(457)),c=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.headingDepth,a=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(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: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"),"."))}},459:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=n(456),c=n(449),i=n.n(c);n(134);t.a=function(e){var t=e.children,n=e.className,o=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),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-"+(s||"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)}},460:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},461: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.977493ae.js.LICENSE.txt b/1b633bfd.c6f89b56.js.LICENSE.txt similarity index 100% rename from 1b633bfd.977493ae.js.LICENSE.txt rename to 1b633bfd.c6f89b56.js.LICENSE.txt diff --git a/1be78505.01f0f748.js b/1be78505.67d5f5fb.js similarity index 94% rename from 1be78505.01f0f748.js rename to 1be78505.67d5f5fb.js index 47e5adcb74..907c96b39b 100644 --- a/1be78505.01f0f748.js +++ b/1be78505.67d5f5fb.js @@ -1,2 +1,2 @@ -/*! For license information please see 1be78505.01f0f748.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[38,294],{444:function(e,t,n){"use strict";n.r(t);n(29),n(22),n(21),n(52),n(462);var a=n(0),r=n.n(a),i=n(449),o=n(447),l=n.n(o),s=n(460),c=n(67),u=n(471),d=n(1),p=(n(78),n(472),n(473),n(454)),m=n(466),f=n.n(m);n(463);var b=n(476),g=n(477),h=n(187),y=n.n(h);n(188);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(553),E=n(588),_=n(496),x=n(189),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)))))}},447: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")},471:function(e,t,n){"use strict";n(481);var a=n(0),r=n.n(a),i=n(482),o=n(470),l=n(1),s=(n(472),n(473),n(483),n(454)),c=n(484),u=n(466),d=n.n(u),p=n(485),m=n.n(p),f=n(460),b=n(447),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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),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(486),F=n(487),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)))}},474:function(e,t,n){"use strict";var a=n(9),r=n(0),i=n.n(r),o=n(447),l=n.n(o),s=n(460),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)}}},478:function(e,t,n){"use strict";var a=n(0),r=Object(a.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=r},489:function(e,t,n){var a=n(30),r=n(54),i=n(27),o=n(26),l=n(490);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}}},490:function(e,t,n){var a=n(491);e.exports=function(e,t){return new(a(e))(t)}},491:function(e,t,n){var a=n(13),r=n(492),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}},492:function(e,t,n){var a=n(23);e.exports=Array.isArray||function(e){return"Array"==a(e)}},511:function(e,t,n){"use strict";(function(e){var a=n(1),r=(n(472),n(473),n(78),n(77),n(554),n(0)),i=n.n(r),o=n(555),l=n.n(o),s=n(587),c=n(53),u=n(447),d=n.n(u),p=n(567),m=n.n(p),f=n(556),b=n.n(f),g=n(460),h=n(467),y=n(148),v=n.n(y);(void 0!==e?e:window).Prism=c.a,n(557),n(558),n(559),n(560),n(90),n(561),n(562),n(563),n(564),n(565),n(566);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))},553:function(e,t,n){"use strict";var a=n(1),r=n(0),i=n.n(r),o=n(454),l=n(511),s=n(474),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")}},554: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}]}))},555: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()},556: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)}))}},557: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)},558: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:/[\[\](){},;]|\.+|:+/}},559: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)},560: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)},561: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)},562: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)},563: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)},564: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},565: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)},566: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)},567: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)"}}]}},587: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(555),E=n(590),_=n(498),x=n(189),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)))))}},449: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")},473:function(e,t,n){"use strict";n(483);var a=n(0),r=n.n(a),i=n(484),o=n(472),l=n(1),s=(n(474),n(475),n(485),n(456)),c=n(486),u=n(468),d=n.n(u),p=n(487),m=n.n(p),f=n(462),b=n(449),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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),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(488),F=n(489),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)))}},476:function(e,t,n){"use strict";var a=n(9),r=n(0),i=n.n(r),o=n(449),l=n.n(o),s=n(462),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)}}},480:function(e,t,n){"use strict";var a=n(0),r=Object(a.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=r},491:function(e,t,n){var a=n(30),r=n(54),i=n(27),o=n(26),l=n(492);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}}},492:function(e,t,n){var a=n(493);e.exports=function(e,t){return new(a(e))(t)}},493:function(e,t,n){var a=n(13),r=n(494),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}},494:function(e,t,n){var a=n(23);e.exports=Array.isArray||function(e){return"Array"==a(e)}},513:function(e,t,n){"use strict";(function(e){var a=n(1),r=(n(474),n(475),n(78),n(77),n(556),n(0)),i=n.n(r),o=n(557),l=n.n(o),s=n(589),c=n(53),u=n(449),d=n.n(u),p=n(569),m=n.n(p),f=n(558),b=n.n(f),g=n(462),h=n(469),y=n(148),v=n.n(y);(void 0!==e?e:window).Prism=c.a,n(559),n(560),n(561),n(562),n(90),n(563),n(564),n(565),n(566),n(567),n(568);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))},555:function(e,t,n){"use strict";var a=n(1),r=n(0),i=n.n(r),o=n(456),l=n(513),s=n(476),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")}},556: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}]}))},557: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()},558: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)}))}},559: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)},560: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:/[\[\](){},;]|\.+|:+/}},561: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)},562: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)},563: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)},564: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)},565: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)},566: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},567: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)},568: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)},569: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)"}}]}},589: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],X=Object(u.useState)(!1),Q=X[0],ee=X[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})),Q&&r.a.createElement(p.a,{className:"modal",onRequestClose:function(){return ee(!1)},overlayClassName:"modal-overlay",isOpen:null!==Q,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}))))}},448:function(e,t,n){"use strict";n(450);var u=n(0),r=n.n(u),a=n(447),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)}},452: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""}}})},457:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=n(454),d=n(447),o=n.n(d);n(134);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)}},461:function(e,t,n){"use strict";var u=n(1),r=(n(465),n(462),n(52),n(29),n(22),n(21),n(0)),a=n.n(r),d=n(469),o=n(447),i=n.n(o),c=n(455),l=n.n(c),f=n(468),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])}},464: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)}},467:function(e,t,n){"use strict";var u=n(0),r=n(509);t.a=function(){return Object(u.useContext)(r.a)}},471:function(e,t,n){"use strict";n(481);var u=n(0),r=n.n(u),a=n(482),d=n(470),o=n(1),i=(n(472),n(473),n(483),n(454)),c=n(484),l=n(466),f=n.n(l),s=n(485),p=n.n(s),m=n(460),h=n(447),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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),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(486),z=n(487),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)))}},474:function(e,t,n){"use strict";var u=n(9),r=n(0),a=n.n(r),d=n(447),o=n.n(d),i=n(460),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)}}},475: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?/,X=/\{\n\/\* \[wrapped with (.+)\] \*/,Q=/,? & /,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,Xe=function(){try{var e=Ze&&Ze.require&&Ze.require("util").types;return e||Ye&&Ye.binding&&Ye.binding("util")}catch(t){}}(),Qe=Xe&&Xe.isArrayBuffer,et=Xe&&Xe.isDate,tt=Xe&&Xe.isMap,nt=Xe&&Xe.isRegExp,ut=Xe&&Xe.isSet,rt=Xe&&Xe.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,Xe=Te?Te.iterator:void 0,gt=Te?Te.toStringTag:void 0,St=function(){try{var e=Qr(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,Xt=me.ceil,Qt=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=Qr(t,"DataView"),pn=Qr(t,"Map"),mn=Qr(t,"Promise"),hn=Qr(t,"Set"),bn=Qr(t,"WeakMap"),vn=Qr(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 Xn(e,t,n){if("function"!=typeof e)throw new ge(a);return ya((function(){e.apply(void 0,n)}),t)}function Qn(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):Qu(e,r)}}return e}function Mu(e,t){return e+Qt(ln()*(t-e+1))}function Ru(e,t){var n="";if(!e||t<1||t>9007199254740991)return n;do{t%2&&(n+=e),(t=Qt(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(X);return t?t[1].split(Q):[]}(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 Xn(e,1,t)})),Ed=Lu((function(e,t,n){return Xn(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=Qe?At(Qe):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 Xd=Tr(Su),Qd=Tr((function(e,t){return e<=t}));function eo(e){if(!e)return[];if(Td(e))return Zd(e)?Gt(e):vr(e);if(Xe&&e[Xe])return function(e){for(var t,n=[];!(t=e.next()).done;)n.push(t.value);return n}(e[Xe]());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--;)Qu(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 Xo=jr(pt),Qo=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(Xt(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?Xu(e):[]},On.uniqBy=function(e,t){return e&&e.length?Xu(e,Jr(t,2)):[]},On.uniqWith=function(e,t){return t="function"==typeof t?t:void 0,e&&e.length?Xu(e,void 0,t):[]},On.unset=function(e,t){return null==e||Qu(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=Xa,On.zipObject=function(e,t){return rr(e||[],t||[],Hn)},On.zipObjectDeep=function(e,t){return rr(e||[],t||[],Uu)},On.zipWith=Qa,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=Xd,On.lte=Qd,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(Qt(r),n)+e+Nr(Xt(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,Xe&&(On.prototype[Xe]=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(480)(e))},476: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])}},477:function(e,t,n){"use strict";var u=n(460),r=n(467),a=n(463),d=n(458);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}}},479:function(e,t,n){"use strict";n.d(t,"a",(function(){return a}));n(77),n(497),n(462),n(78);var u=n(499),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)}))}},480: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}},481:function(e,t,n){"use strict";var u=n(12),r=n(26),a=n(541),d="".endsWith;u(u.P+u.F*n(542)("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}})},482:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=n(460),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")))}},483:function(e,t,n){"use strict";var u=n(0);u.PureComponent},484: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(447),d=n.n(a),o=n(460),i=n(496);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(293).then(n.t.bind(null,594,7)),n.e(194).then(n.t.bind(null,607,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}))}},485: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})])}},486:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=(n(84),n(497),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}},494:function(e,t,n){"use strict";var u=n(533);e.exports=Function.prototype.bind||u},495: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}},496: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}))},498:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=n(454),d=n(447),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,")"))}},499:function(e,t,n){var u=n(500);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},500: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}},502:function(e,t,n){"use strict";var u=n(495),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},509: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},511:function(e,t,n){"use strict";(function(e){var u=n(1),r=(n(472),n(473),n(78),n(77),n(554),n(0)),a=n.n(r),d=n(555),o=n.n(d),i=n(587),c=n(53),l=n(447),f=n.n(l),s=n(567),p=n.n(s),m=n(556),h=n.n(m),b=n(460),v=n(467),g=n(148),y=n.n(g);(void 0!==e?e:window).Prism=c.a,n(557),n(558),n(559),n(560),n(90),n(561),n(562),n(563),n(564),n(565),n(566);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))},512:function(e,t,n){"use strict";var u=n(0),r=n.n(u);n(448),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"))}},513: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(569),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}})},514:function(e,t,n){"use strict";var u=n(570),r=n(516);e.exports=n(571)("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)},515: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}}},516: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}},517:function(e,t,n){"use strict";const u=n(518);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()}},518:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u=f(n(519)),r=f(n(520)),a=f(n(521)),d=f(n(522)),o=f(n(523)),i=f(n(524)),c=f(n(525)),l=f(n(526));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},519: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},520: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},521: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},522: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},525: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},526: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},527: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))}},528:function(e,t,n){"use strict";var u=n(529),r=n(539),a=n(495);e.exports={formats:a,parse:r,stringify:u}},529:function(e,t,n){"use strict";var u=n(530),r=n(502),a=n(495),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+_:""}},530:function(e,t,n){"use strict";var u=n(493),r=n(535),a=n(537),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}},531:function(e,t,n){"use strict";var u="undefined"!=typeof Symbol&&Symbol,r=n(532);e.exports=function(){return"function"==typeof u&&("function"==typeof Symbol&&("symbol"==typeof u("foo")&&("symbol"==typeof Symbol("bar")&&r())))}},532: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}},533: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}},536:function(e,t,n){"use strict";var u=n(494),r=n(493),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},537: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(538),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),Q=X(t,M);return"[Function"+(H?": "+H:" (anonymous)")+"]"+(Q.length>0?" { "+k.call(Q,", ")+" }":"")}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=X(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=X(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=X(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}}},551:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=n(454),d=n(447),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"))))}},552: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()},556: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)}))}},557: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)},558: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:/[\[\](){},;]|\.+|:+/}},559: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)},560: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)},561: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)},562: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)},563: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)},564: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},565: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)},566: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)},567: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)"}}]}},568:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.canUseDOM=void 0;var u,r=n(589);var a=((u=r)&&u.__esModule?u:{default:u}).default,d=a.canUseDOM?window.HTMLElement:{};t.canUseDOM=a.canUseDOM;t.default=d},569: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}},570: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(515).fastKey,m=n(516),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)}}},571:function(e,t,n){"use strict";var u=n(5),r=n(12),a=n(16),d=n(82),o=n(515),i=n(81),c=n(80),l=n(13),f=n(14),s=n(83),p=n(41),m=n(572);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}},572:function(e,t,n){var u=n(13),r=n(573).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}},573: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(574).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}},574: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])}},575: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(576)(o)),"Array",{sort:function(e){return void 0===e?o.call(a(this)):o.call(a(this),r(e))}})},576: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)}))}},585:function(e,t,n){"use strict";n(513),n(79),n(514),n(575),n(29),n(22),n(21),n(85),n(465);var u=n(1),r=(n(472),n(473),n(77),n(452),n(0)),a=n.n(r),d=n(505),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(527),l=n(457),f=n(454),s=(n(466),n(475)),p=n.n(s),m=n(447),h=n.n(m),b=n(528),v=n.n(b),g=n(460);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})))}},587: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},592: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(617),a=(u=r)&&u.__esModule?u:{default:u},d=n(568);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)}},593: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},612:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u,r=n(613),a=(u=r)&&u.__esModule?u:{default:u};t.default=a.default,e.exports=t.default},613: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},615: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(591),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)}}},616: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(591),a=(u=r)&&u.__esModule?u:{default:u};e.exports=t.default},617:function(e,t,n){"use strict";var u=function(){};e.exports=u},618: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}},619:function(e,t,n){"use strict";var u,r=n(593),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))}))},620: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},621: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],X=Object(u.useState)(!1),Q=X[0],ee=X[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})),Q&&r.a.createElement(p.a,{className:"modal",onRequestClose:function(){return ee(!1)},overlayClassName:"modal-overlay",isOpen:null!==Q,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}))))}},450:function(e,t,n){"use strict";n(452);var u=n(0),r=n.n(u),a=n(449),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)}},454: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""}}})},459:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=n(456),d=n(449),o=n.n(d);n(134);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)}},463:function(e,t,n){"use strict";var u=n(1),r=(n(467),n(464),n(52),n(29),n(22),n(21),n(0)),a=n.n(r),d=n(471),o=n(449),i=n.n(o),c=n(457),l=n.n(c),f=n(470),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])}},466: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)}},469:function(e,t,n){"use strict";var u=n(0),r=n(511);t.a=function(){return Object(u.useContext)(r.a)}},473:function(e,t,n){"use strict";n(483);var u=n(0),r=n.n(u),a=n(484),d=n(472),o=n(1),i=(n(474),n(475),n(485),n(456)),c=n(486),l=n(468),f=n.n(l),s=n(487),p=n.n(s),m=n(462),h=n(449),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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),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(488),z=n(489),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)))}},476:function(e,t,n){"use strict";var u=n(9),r=n(0),a=n.n(r),d=n(449),o=n.n(d),i=n(462),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)}}},477: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?/,X=/\{\n\/\* \[wrapped with (.+)\] \*/,Q=/,? & /,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,Xe=function(){try{var e=Ze&&Ze.require&&Ze.require("util").types;return e||Ye&&Ye.binding&&Ye.binding("util")}catch(t){}}(),Qe=Xe&&Xe.isArrayBuffer,et=Xe&&Xe.isDate,tt=Xe&&Xe.isMap,nt=Xe&&Xe.isRegExp,ut=Xe&&Xe.isSet,rt=Xe&&Xe.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,Xe=Te?Te.iterator:void 0,gt=Te?Te.toStringTag:void 0,St=function(){try{var e=Qr(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,Xt=me.ceil,Qt=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=Qr(t,"DataView"),pn=Qr(t,"Map"),mn=Qr(t,"Promise"),hn=Qr(t,"Set"),bn=Qr(t,"WeakMap"),vn=Qr(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 Xn(e,t,n){if("function"!=typeof e)throw new ge(a);return ya((function(){e.apply(void 0,n)}),t)}function Qn(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):Qu(e,r)}}return e}function Mu(e,t){return e+Qt(ln()*(t-e+1))}function Ru(e,t){var n="";if(!e||t<1||t>9007199254740991)return n;do{t%2&&(n+=e),(t=Qt(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(X);return t?t[1].split(Q):[]}(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 Xn(e,1,t)})),Ed=Lu((function(e,t,n){return Xn(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=Qe?At(Qe):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 Xd=Tr(Su),Qd=Tr((function(e,t){return e<=t}));function eo(e){if(!e)return[];if(Td(e))return Zd(e)?Gt(e):vr(e);if(Xe&&e[Xe])return function(e){for(var t,n=[];!(t=e.next()).done;)n.push(t.value);return n}(e[Xe]());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--;)Qu(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 Xo=jr(pt),Qo=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(Xt(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?Xu(e):[]},On.uniqBy=function(e,t){return e&&e.length?Xu(e,Jr(t,2)):[]},On.uniqWith=function(e,t){return t="function"==typeof t?t:void 0,e&&e.length?Xu(e,void 0,t):[]},On.unset=function(e,t){return null==e||Qu(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=Xa,On.zipObject=function(e,t){return rr(e||[],t||[],Hn)},On.zipObjectDeep=function(e,t){return rr(e||[],t||[],Uu)},On.zipWith=Qa,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=Xd,On.lte=Qd,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(Qt(r),n)+e+Nr(Xt(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,Xe&&(On.prototype[Xe]=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(482)(e))},478: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])}},479:function(e,t,n){"use strict";var u=n(462),r=n(469),a=n(465),d=n(460);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}}},481:function(e,t,n){"use strict";n.d(t,"a",(function(){return a}));n(77),n(499),n(464),n(78);var u=n(501),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)}))}},482: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}},483:function(e,t,n){"use strict";var u=n(12),r=n(26),a=n(543),d="".endsWith;u(u.P+u.F*n(544)("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}})},484:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=n(462),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")))}},485:function(e,t,n){"use strict";var u=n(0);u.PureComponent},486: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(449),d=n.n(a),o=n(462),i=n(498);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(295).then(n.t.bind(null,596,7)),n.e(196).then(n.t.bind(null,609,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}))}},487: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})])}},488:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=(n(84),n(499),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}},496:function(e,t,n){"use strict";var u=n(535);e.exports=Function.prototype.bind||u},497: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}},498: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}))},500:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=n(456),d=n(449),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,")"))}},501:function(e,t,n){var u=n(502);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},502: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}},504:function(e,t,n){"use strict";var u=n(497),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},511: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},513:function(e,t,n){"use strict";(function(e){var u=n(1),r=(n(474),n(475),n(78),n(77),n(556),n(0)),a=n.n(r),d=n(557),o=n.n(d),i=n(589),c=n(53),l=n(449),f=n.n(l),s=n(569),p=n.n(s),m=n(558),h=n.n(m),b=n(462),v=n(469),g=n(148),y=n.n(g);(void 0!==e?e:window).Prism=c.a,n(559),n(560),n(561),n(562),n(90),n(563),n(564),n(565),n(566),n(567),n(568);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))},514:function(e,t,n){"use strict";var u=n(0),r=n.n(u);n(450),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"))}},515: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(571),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}})},516:function(e,t,n){"use strict";var u=n(572),r=n(518);e.exports=n(573)("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)},517: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}}},518: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}},519:function(e,t,n){"use strict";const u=n(520);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()}},520:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u=f(n(521)),r=f(n(522)),a=f(n(523)),d=f(n(524)),o=f(n(525)),i=f(n(526)),c=f(n(527)),l=f(n(528));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},521: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},522: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},523: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},524: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},527: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},528: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},529: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))}},530:function(e,t,n){"use strict";var u=n(531),r=n(541),a=n(497);e.exports={formats:a,parse:r,stringify:u}},531:function(e,t,n){"use strict";var u=n(532),r=n(504),a=n(497),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+_:""}},532:function(e,t,n){"use strict";var u=n(495),r=n(537),a=n(539),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}},533:function(e,t,n){"use strict";var u="undefined"!=typeof Symbol&&Symbol,r=n(534);e.exports=function(){return"function"==typeof u&&("function"==typeof Symbol&&("symbol"==typeof u("foo")&&("symbol"==typeof Symbol("bar")&&r())))}},534: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}},535: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}},538:function(e,t,n){"use strict";var u=n(496),r=n(495),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},539: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(540),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),Q=X(t,M);return"[Function"+(H?": "+H:" (anonymous)")+"]"+(Q.length>0?" { "+k.call(Q,", ")+" }":"")}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=X(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=X(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=X(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}}},553:function(e,t,n){"use strict";var u=n(0),r=n.n(u),a=n(456),d=n(449),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"))))}},554: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()},558: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)}))}},559: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)},560: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:/[\[\](){},;]|\.+|:+/}},561: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)},562: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)},563: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)},564: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)},565: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)},566: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},567: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)},568: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)},569: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)"}}]}},570:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.canUseDOM=void 0;var u,r=n(591);var a=((u=r)&&u.__esModule?u:{default:u}).default,d=a.canUseDOM?window.HTMLElement:{};t.canUseDOM=a.canUseDOM;t.default=d},571: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}},572: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(517).fastKey,m=n(518),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)}}},573:function(e,t,n){"use strict";var u=n(5),r=n(12),a=n(16),d=n(82),o=n(517),i=n(81),c=n(80),l=n(13),f=n(14),s=n(83),p=n(41),m=n(574);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}},574:function(e,t,n){var u=n(13),r=n(575).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}},575: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(576).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}},576: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])}},577: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(578)(o)),"Array",{sort:function(e){return void 0===e?o.call(a(this)):o.call(a(this),r(e))}})},578: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)}))}},587:function(e,t,n){"use strict";n(515),n(79),n(516),n(577),n(29),n(22),n(21),n(85),n(467);var u=n(1),r=(n(474),n(475),n(77),n(454),n(0)),a=n.n(r),d=n(507),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(529),l=n(459),f=n(456),s=(n(468),n(477)),p=n.n(s),m=n(449),h=n.n(m),b=n(530),v=n.n(b),g=n(462);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})))}},589: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},594: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(619),a=(u=r)&&u.__esModule?u:{default:u},d=n(570);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)}},595: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},614:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u,r=n(615),a=(u=r)&&u.__esModule?u:{default:u};t.default=a.default,e.exports=t.default},615: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},617: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(593),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)}}},618: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(593),a=(u=r)&&u.__esModule?u:{default:u};e.exports=t.default},619:function(e,t,n){"use strict";var u=function(){};e.exports=u},620: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}},621:function(e,t,n){"use strict";var u,r=n(595),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))}))},622: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},623: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},454:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(458),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}))}},457:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(454),i=n(447),c=n.n(i);n(134);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)}},458: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 1d187ae3.f2a8f8b3.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[40],{192: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(451)),i=n(450),c=(n(459),n(455),{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:"Labels & Annotations",permalink:"/docs/using-qovery/configuration/organization/labels-annotations"}},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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},456:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(460),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}))}},459:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(456),i=n(449),c=n.n(i);n(134);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)}},460: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.03063d7b.js.LICENSE.txt b/1d187ae3.f2a8f8b3.js.LICENSE.txt similarity index 100% rename from 1d187ae3.03063d7b.js.LICENSE.txt rename to 1d187ae3.f2a8f8b3.js.LICENSE.txt diff --git a/1d3be599.f7d7cade.js b/1d3be599.d6f555a0.js similarity index 90% rename from 1d3be599.f7d7cade.js rename to 1d3be599.d6f555a0.js index 44743e574d..1061212c3b 100644 --- a/1d3be599.f7d7cade.js +++ b/1d3be599.d6f555a0.js @@ -1,2 +1,2 @@ -/*! For license information please see 1d3be599.f7d7cade.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[41],{193: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(449)),i=n(456),c=n(448),s=n(453),u=(n(457),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},454:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),c=n(458),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}))}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(447),n(455)),i=n.n(a);n(133);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"),"."))}},457:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(454),i=n(447),c=n.n(i);n(134);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)}},458:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},459: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.d6f555a0.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[41],{193: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(451)),i=n(458),c=n(450),s=n(455),u=(n(459),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},456:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),c=n(460),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}))}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(449),n(457)),i=n.n(a);n(133);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"),"."))}},459:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(456),i=n(449),c=n.n(i);n(134);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)}},460:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},461: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/1d3be599.f7d7cade.js.LICENSE.txt b/1d3be599.d6f555a0.js.LICENSE.txt similarity index 100% rename from 1d3be599.f7d7cade.js.LICENSE.txt rename to 1d3be599.d6f555a0.js.LICENSE.txt diff --git a/1dd2c233.ef04d552.js b/1dd2c233.a145199c.js similarity index 93% rename from 1dd2c233.ef04d552.js rename to 1dd2c233.a145199c.js index addefe9127..7c31e532cf 100644 --- a/1dd2c233.ef04d552.js +++ b/1dd2c233.a145199c.js @@ -1,2 +1,2 @@ -/*! For license information please see 1dd2c233.ef04d552.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[42],{194: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(449)),c=(r(456),r(453),r(448)),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 JupyterHub using Helm",permalink:"/guides/tutorial/deploy-jupyterhub-qovery"}},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},447: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)},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,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,m=p["".concat(c,".").concat(d)]||p[d]||b[d]||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]=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}},452: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""}}})},453:function(e,t,r){"use strict";r(452);var n=r(0),a=r.n(n),o=r(448);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)}},455:function(e,t,r){"use strict";var n=r(459),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("&"):""}},456:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(447),r(455)),c=r.n(o);r(133);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],b=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 b("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"),"."))}},459: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.a145199c.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[42],{194: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(451)),c=(r(458),r(455),r(450)),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 JupyterHub using Helm",permalink:"/guides/tutorial/deploy-jupyterhub-qovery"}},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},449: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)},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,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,m=p["".concat(c,".").concat(d)]||p[d]||b[d]||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]=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}},454: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""}}})},455:function(e,t,r){"use strict";r(454);var n=r(0),a=r.n(n),o=r(450);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)}},457:function(e,t,r){"use strict";var n=r(461),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("&"):""}},458:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(449),r(457)),c=r.n(o);r(133);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],b=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 b("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"),"."))}},461: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/1dd2c233.ef04d552.js.LICENSE.txt b/1dd2c233.a145199c.js.LICENSE.txt similarity index 100% rename from 1dd2c233.ef04d552.js.LICENSE.txt rename to 1dd2c233.a145199c.js.LICENSE.txt diff --git a/2.f872e5b2.js b/2.1dcc0ed7.js similarity index 92% rename from 2.f872e5b2.js rename to 2.1dcc0ed7.js index 6760ca66f0..3d6effb5bd 100644 --- a/2.f872e5b2.js +++ b/2.1dcc0ed7.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[2],{454:function(t,e,n){"use strict";var r=n(1),o=n(0),i=n.n(o),a=n(39),c=n(458),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}))}},458:function(t,e,n){"use strict";function r(t){return!1===/^(https?:|\/\/)/.test(t)}n.d(e,"a",(function(){return r}))},460:function(t,e,n){"use strict";var r=n(0),o=n(69);e.a=function(){return Object(r.useContext)(o.a)}},463:function(t,e,n){"use strict";n.d(e,"a",(function(){return o}));n(497);var r=n(460);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}},470:function(t,e,n){"use strict";var r=n(0),o=n.n(r),i=n(608);e.a=function(t){return o.a.createElement(i.a,t)}},472: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")},473:function(t,e,n){"use strict";var r=n(12),o=n(541);r(r.P+r.F*n(542)("includes"),"String",{includes:function(t){return!!~o(this,t,"includes").indexOf(t,arguments.length>1?arguments[1]:void 0)}})},497:function(t,e,n){"use strict";var r=n(12),o=n(26),i=n(541),a="".startsWith;r(r.P+r.F*n(542)("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}})},541: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))}},542: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}},608: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(609),f=n.n(s),l=n(610),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))},609: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}}},610: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],{456:function(t,e,n){"use strict";var r=n(1),o=n(0),i=n.n(o),a=n(39),c=n(460),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}))}},460:function(t,e,n){"use strict";function r(t){return!1===/^(https?:|\/\/)/.test(t)}n.d(e,"a",(function(){return r}))},462:function(t,e,n){"use strict";var r=n(0),o=n(69);e.a=function(){return Object(r.useContext)(o.a)}},465:function(t,e,n){"use strict";n.d(e,"a",(function(){return o}));n(499);var r=n(462);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}},472:function(t,e,n){"use strict";var r=n(0),o=n.n(r),i=n(610);e.a=function(t){return o.a.createElement(i.a,t)}},474: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")},475:function(t,e,n){"use strict";var r=n(12),o=n(543);r(r.P+r.F*n(544)("includes"),"String",{includes:function(t){return!!~o(this,t,"includes").indexOf(t,arguments.length>1?arguments[1]:void 0)}})},499:function(t,e,n){"use strict";var r=n(12),o=n(26),i=n(543),a="".startsWith;r(r.P+r.F*n(544)("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}})},543: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))}},544: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}},610: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(611),f=n.n(s),l=n(612),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))},611: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}}},612: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/2121549d.44acaeb9.js b/2121549d.adedd60e.js similarity index 98% rename from 2121549d.44acaeb9.js rename to 2121549d.adedd60e.js index e0ee83dbc7..ebcb411c6d 100644 --- a/2121549d.44acaeb9.js +++ b/2121549d.adedd60e.js @@ -1 +1 @@ -(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 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(449)),i=n(448),l=(n(461),n(453)),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},448:function(e,t,n){"use strict";n(450);var a=n(0),o=n.n(a),r=n(447),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)}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),o=n.n(a),r=n(448);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)}},461:function(e,t,n){"use strict";var a=n(1),o=(n(465),n(462),n(52),n(29),n(22),n(21),n(0)),r=n.n(o),i=n(469),l=n(447),s=n.n(l),c=n(455),b=n.n(c),u=n(468),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([[45],{197: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(451)),i=n(450),l=(n(463),n(455)),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},450:function(e,t,n){"use strict";n(452);var a=n(0),o=n.n(a),r=n(449),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)}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),o=n.n(a),r=n(450);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)}},463:function(e,t,n){"use strict";var a=n(1),o=(n(467),n(464),n(52),n(29),n(22),n(21),n(0)),r=n.n(o),i=n(471),l=n(449),s=n.n(l),c=n(457),b=n.n(c),u=n(470),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/225ad2ad.329a2268.js b/225ad2ad.9c456f2d.js similarity index 89% rename from 225ad2ad.329a2268.js rename to 225ad2ad.9c456f2d.js index d2c24e6644..3ed516e4cc 100644 --- a/225ad2ad.329a2268.js +++ b/225ad2ad.9c456f2d.js @@ -1,2 +1,2 @@ -/*! For license information please see 225ad2ad.329a2268.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[46],{198: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 p}));var r=n(1),a=n(9),i=(n(0),n(449)),o=n(448),l={last_modified_on:"2024-01-02",$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",series_position:1,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: aws"]},c={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery on your Amazon Web Services account",description:"Learn how to install Qovery on your Amazon Web Services (AWS) account",permalink:"/guides/installation-guide/guide-amazon-web-services",readingTime:"1 min read",seriesPosition:1,source:"@site/guides/installation-guide/guide-amazon-web-services.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: aws",permalink:"/guides/tags/installation-guide-aws"}],title:"Install Qovery on your Amazon Web Services account",truncated:!1,prevItem:{title:"Debugging",permalink:"/guides/getting-started/debugging"},nextItem:{title:"Install Qovery your Google Cloud Platform account",permalink:"/guides/installation-guide/guide-google-cloud-platform"}},u=[],s={rightToc:u};function p(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(i.b)("wrapper",Object(r.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(o.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"Access our new installation guide of Qovery on AWS ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/"}),"here"))))}p.isMDXComponent=!0},447: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 i=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):l({},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)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,o=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,g=p["".concat(o,".").concat(d)]||p[d]||f[d]||i;return n?a.a.createElement(g,l({ref:t},u,{components:n})):a.a.createElement(g,l({ref:t},u))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[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,o[1]=l;for(var u=2;u1?arguments[1]:void 0,n),c=o>2?arguments[2]:void 0,u=void 0===c?n:a(c,n);u>l;)t[l++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see 225ad2ad.9c456f2d.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[46],{198: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 p}));var r=n(1),a=n(9),i=(n(0),n(451)),o=n(450),l={last_modified_on:"2024-01-02",$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",series_position:1,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: aws"]},c={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery on your Amazon Web Services account",description:"Learn how to install Qovery on your Amazon Web Services (AWS) account",permalink:"/guides/installation-guide/guide-amazon-web-services",readingTime:"1 min read",seriesPosition:1,source:"@site/guides/installation-guide/guide-amazon-web-services.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: aws",permalink:"/guides/tags/installation-guide-aws"}],title:"Install Qovery on your Amazon Web Services account",truncated:!1,prevItem:{title:"Debugging",permalink:"/guides/getting-started/debugging"},nextItem:{title:"Install Qovery your Google Cloud Platform account",permalink:"/guides/installation-guide/guide-google-cloud-platform"}},u=[],s={rightToc:u};function p(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(i.b)("wrapper",Object(r.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(o.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"Access our new installation guide of Qovery on AWS ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/"}),"here"))))}p.isMDXComponent=!0},449: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 i=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):l({},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)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,o=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,g=p["".concat(o,".").concat(d)]||p[d]||f[d]||i;return n?a.a.createElement(g,l({ref:t},u,{components:n})):a.a.createElement(g,l({ref:t},u))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[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,o[1]=l;for(var u=2;u1?arguments[1]:void 0,n),c=o>2?arguments[2]:void 0,u=void 0===c?n:a(c,n);u>l;)t[l++]=e;return t}}}]); \ No newline at end of file diff --git a/225ad2ad.329a2268.js.LICENSE.txt b/225ad2ad.9c456f2d.js.LICENSE.txt similarity index 100% rename from 225ad2ad.329a2268.js.LICENSE.txt rename to 225ad2ad.9c456f2d.js.LICENSE.txt diff --git a/2309a9c8.4b1ed172.js b/2309a9c8.4555b680.js similarity index 91% rename from 2309a9c8.4b1ed172.js rename to 2309a9c8.4555b680.js index 411f7e62b9..2caa856e5a 100644 --- a/2309a9c8.4b1ed172.js +++ b/2309a9c8.4555b680.js @@ -1,2 +1,2 @@ -/*! For license information please see 2309a9c8.4b1ed172.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[47],{199: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(449)),i=(a(456),a(453),a(448),{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},447: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}},452: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""}}})},453:function(e,t,a){"use strict";a(452);var r=a(0),n=a.n(r),o=a(448);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)}},455:function(e,t,a){"use strict";var r=a(459),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("&"):""}},456:function(e,t,a){"use strict";var r=a(0),n=a.n(r),o=(a(447),a(455)),i=a.n(o);a(133);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"),"."))}},459: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.4555b680.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[47],{199: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(451)),i=(a(458),a(455),a(450),{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},449: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}},454: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""}}})},455:function(e,t,a){"use strict";a(454);var r=a(0),n=a.n(r),o=a(450);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)}},457:function(e,t,a){"use strict";var r=a(461),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("&"):""}},458:function(e,t,a){"use strict";var r=a(0),n=a.n(r),o=(a(449),a(457)),i=a.n(o);a(133);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"),"."))}},461: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/2309a9c8.4b1ed172.js.LICENSE.txt b/2309a9c8.4555b680.js.LICENSE.txt similarity index 100% rename from 2309a9c8.4b1ed172.js.LICENSE.txt rename to 2309a9c8.4555b680.js.LICENSE.txt diff --git a/2486bcfc.bd2091af.js b/2486bcfc.f0859e1a.js similarity index 97% rename from 2486bcfc.bd2091af.js rename to 2486bcfc.f0859e1a.js index 2faa1557be..b301f9f1a7 100644 --- a/2486bcfc.bd2091af.js +++ b/2486bcfc.f0859e1a.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[48],{200: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(449)),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},449: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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.6460e105.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[49],{201: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(451)),i=n(458),c=n(455),s=(n(450),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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/24e60f8a.32e1faf2.js.LICENSE.txt b/24e60f8a.6460e105.js.LICENSE.txt similarity index 100% rename from 24e60f8a.32e1faf2.js.LICENSE.txt rename to 24e60f8a.6460e105.js.LICENSE.txt diff --git a/256f5506.578ccff8.js b/256f5506.84ef9839.js similarity index 96% rename from 256f5506.578ccff8.js rename to 256f5506.84ef9839.js index e18d62201f..4e7817a599 100644 --- a/256f5506.578ccff8.js +++ b/256f5506.84ef9839.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[50],{202: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 u})),r.d(t,"default",(function(){return s}));var n=r(1),o=r(9),a=(r(0),r(449)),c={last_modified_on:"2023-12-30",title:"Quickstart",description:"Learn how to configure and plug your Microsoft Azure account"},i={id:"getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart",title:"Quickstart",description:"Learn how to configure and plug your Microsoft Azure account",source:"@site/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart.md",permalink:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart",sidebar:"docs",previous:{title:"Managed By Qovery",permalink:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery"},next:{title:"Self-Managed Cluster",permalink:"/docs/getting-started/install-qovery/azure/self-managed-cluster"}},u=[],l={rightToc:u};function s(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,"We plan to provide a Managed Kubernetes offer for Microsoft Azure in the future. In the meantime, you can ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/quickstart/"}),"install Qovery on your own Azure Kubernetes Service (AKS) cluster"),"."))}s.isMDXComponent=!0},449:function(e,t,r){"use strict";r.d(t,"a",(function(){return p})),r.d(t,"b",(function(){return y}));var n=r(0),o=r.n(n);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 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||(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({}),s=function(e){var t=o.a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},p=function(e){var t=s(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(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,c=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,y=p["".concat(c,".").concat(d)]||p[d]||f[d]||a;return r?o.a.createElement(y,i({ref:t},l,{components:r})):o.a.createElement(y,i({ref:t},l))}));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 u in t)hasOwnProperty.call(t,u)&&(i[u]=t[u]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;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({}),s=function(e){var t=o.a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},p=function(e){var t=s(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(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,c=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,y=p["".concat(c,".").concat(d)]||p[d]||f[d]||a;return r?o.a.createElement(y,i({ref:t},l,{components:r})):o.a.createElement(y,i({ref:t},l))}));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 u in t)hasOwnProperty.call(t,u)&&(i[u]=t[u]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var l=2;l Helm Repositories"),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/helm_repository_1.png",alt:"Helm"})),Object(o.b)("h3",{id:"create-a-helm-repository"},"Create a Helm Repository"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/organization/helm_repository_creation.png",alt:"Helm"})),Object(o.b)("p",null,'By clicking on "Add Repository" you will be able to create a new Helm Repository by filling these information:'),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Repository Name"),Object(o.b)("li",{parentName:"ul"},"Description"),Object(o.b)("li",{parentName:"ul"},"Kind:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"HTTP: for standard helm repository"),Object(o.b)("li",{parentName:"ul"},"OCI_ECR: for AWS private OCI-based registries"),Object(o.b)("li",{parentName:"ul"},"OCI_SCALEWAY: for Scaleway OCI-based registries"),Object(o.b)("li",{parentName:"ul"},"OCI_DOCKER_HUB: for Docker Hub OCI-based registries"),Object(o.b)("li",{parentName:"ul"},"OCI_PUBLIC_ECR: for AWS public OCI-based registries"),Object(o.b)("li",{parentName:"ul"},"OCI_GENERIC_CR: for Generic OCI-based registries"),Object(o.b)("li",{parentName:"ul"},"OCI_GITHUB_CR: for Github OCI-based registries"),Object(o.b)("li",{parentName:"ul"},"OCI_GITLAB_CR: for Gitlab OCI-based registries"))),Object(o.b)("li",{parentName:"ul"},"Repository Url: the url of the repository (example: oci://registry-1.docker.io/repository, ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://helm.datadoghq.com"}),"https://helm.datadoghq.com")," etc..)"),Object(o.b)("li",{parentName:"ul"},"Credentials: these depend on the chosen repository type. If a helm repository is public, you don't need to fill this part."),Object(o.b)("li",{parentName:"ul"},"Skip TLS verification: to activate the helm argument --insecure-skip-tls-verify")),Object(o.b)("p",null,"Now that you have created the repository, you can start using it in order to ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/#deploying-from-a-helm-repository"}),"create and deploy a helm chart")," using the images stored within it."),Object(o.b)("h3",{id:"modify-or-delete-an-existing-repository"},"Modify or Delete an existing repository"),Object(o.b)("p",null,'You can modify an existing helm repository by clicking on the "Wheel" button next to it\nYou can delete an existing helm repository by clicking on the "Trash" button next to it'),Object(o.b)(a.a,{type:"alert",mdxType:"Alert"},Object(o.b)("p",null,"Before deleting it, make sure there is no helm service within your organization using a helm chart stored in this repository.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/organization/helm_repository_edit.png",alt:"Helm"})))}p.isMDXComponent=!0},447:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function i(){for(var e=[],t=0;t=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var l=i.a.createContext({}),u=function(e){var t=i.a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},p=function(e){var t=u(e.components);return i.a.createElement(l.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},f=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,a=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(r),f=n,b=p["".concat(a,".").concat(f)]||p[f]||m[f]||o;return r?i.a.createElement(b,c({ref:t},l,{components:r})):i.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,a=new Array(o);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 l=2;l1?arguments[1]:void 0,r),s=a>2?arguments[2]:void 0,l=void 0===s?r:i(s,r);l>c;)t[c++]=e;return t}},452:function(e,t,r){var n=r(28).f,i=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in i||r(10)&&n(i,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},453:function(e,t,r){"use strict";r(452);var n=r(0),i=r.n(n),o=r(448);t.a=function(e){var t=e.children,r=e.name;return i.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"},i.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},454:function(e,t,r){"use strict";var n=r(1),i=r(0),o=r.n(i),a=r(39),c=r(458),s=r(20),l=r.n(s);t.a=function(e){var t,r=e.to,s=e.href,u=r||s,p=Object(c.a)(u),m=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?o.a.createElement(a.b,Object(n.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(u),m.current=!0)},innerRef:function(e){var r,n;f&&e&&p&&(r=e,n=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(),n())}))}))).observe(r))},to:u})):o.a.createElement("a",Object(n.a)({},e,{href:u}))}},457:function(e,t,r){"use strict";var n=r(0),i=r.n(n),o=r(454),a=r(447),c=r.n(a);r(134);t.a=function(e){var t=e.children,r=e.className,n=e.badge,a=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,m=c()("jump-to","jump-to--"+l,r),f=i.a.createElement("div",{className:"jump-to--inner"},i.a.createElement("div",{className:"jump-to--inner-2"},a&&i.a.createElement("div",{className:"jump-to--left"},i.a.createElement("i",{className:"feather icon-"+a})),i.a.createElement("div",{className:"jump-to--main"},n?i.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",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:m},f):i.a.createElement(o.a,{to:p,className:m},f)}},458: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 2737c3be.d0d1bcdd.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[52],{204: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 p}));var n=r(1),i=r(9),o=(r(0),r(451)),a=r(450),c=(r(459),r(455),{last_modified_on:"2023-12-19",title:"Helm Repository",description:"Learn how to manage the helm repository allowed in your organization"}),s={id:"using-qovery/configuration/organization/helm-repository",title:"Helm Repository",description:"Learn how to manage the helm repository allowed in your organization",source:"@site/docs/using-qovery/configuration/organization/helm-repository.md",permalink:"/docs/using-qovery/configuration/organization/helm-repository",sidebar:"docs",previous:{title:"Container Registry",permalink:"/docs/using-qovery/configuration/organization/container-registry"},next:{title:"API Token",permalink:"/docs/using-qovery/configuration/organization/api-token"}},l=[{value:"Create a Helm Repository",id:"create-a-helm-repository",children:[]},{value:"Modify or Delete an existing repository",id:"modify-or-delete-an-existing-repository",children:[]}],u={rightToc:l};function p(e){var t=e.components,r=Object(i.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},u,r,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"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."),Object(o.b)("p",null,"You can access this section by opening the Organization Settings -> Helm Repositories"),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/helm_repository_1.png",alt:"Helm"})),Object(o.b)("h3",{id:"create-a-helm-repository"},"Create a Helm Repository"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/organization/helm_repository_creation.png",alt:"Helm"})),Object(o.b)("p",null,'By clicking on "Add Repository" you will be able to create a new Helm Repository by filling these information:'),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Repository Name"),Object(o.b)("li",{parentName:"ul"},"Description"),Object(o.b)("li",{parentName:"ul"},"Kind:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"HTTP: for standard helm repository"),Object(o.b)("li",{parentName:"ul"},"OCI_ECR: for AWS private OCI-based registries"),Object(o.b)("li",{parentName:"ul"},"OCI_SCALEWAY: for Scaleway OCI-based registries"),Object(o.b)("li",{parentName:"ul"},"OCI_DOCKER_HUB: for Docker Hub OCI-based registries"),Object(o.b)("li",{parentName:"ul"},"OCI_PUBLIC_ECR: for AWS public OCI-based registries"),Object(o.b)("li",{parentName:"ul"},"OCI_GENERIC_CR: for Generic OCI-based registries"),Object(o.b)("li",{parentName:"ul"},"OCI_GITHUB_CR: for Github OCI-based registries"),Object(o.b)("li",{parentName:"ul"},"OCI_GITLAB_CR: for Gitlab OCI-based registries"))),Object(o.b)("li",{parentName:"ul"},"Repository Url: the url of the repository (example: oci://registry-1.docker.io/repository, ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://helm.datadoghq.com"}),"https://helm.datadoghq.com")," etc..)"),Object(o.b)("li",{parentName:"ul"},"Credentials: these depend on the chosen repository type. If a helm repository is public, you don't need to fill this part."),Object(o.b)("li",{parentName:"ul"},"Skip TLS verification: to activate the helm argument --insecure-skip-tls-verify")),Object(o.b)("p",null,"Now that you have created the repository, you can start using it in order to ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/#deploying-from-a-helm-repository"}),"create and deploy a helm chart")," using the images stored within it."),Object(o.b)("h3",{id:"modify-or-delete-an-existing-repository"},"Modify or Delete an existing repository"),Object(o.b)("p",null,'You can modify an existing helm repository by clicking on the "Wheel" button next to it\nYou can delete an existing helm repository by clicking on the "Trash" button next to it'),Object(o.b)(a.a,{type:"alert",mdxType:"Alert"},Object(o.b)("p",null,"Before deleting it, make sure there is no helm service within your organization using a helm chart stored in this repository.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/organization/helm_repository_edit.png",alt:"Helm"})))}p.isMDXComponent=!0},449:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function i(){for(var e=[],t=0;t=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var l=i.a.createContext({}),u=function(e){var t=i.a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c({},t,{},e)),r},p=function(e){var t=u(e.components);return i.a.createElement(l.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},f=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,a=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=u(r),f=n,b=p["".concat(a,".").concat(f)]||p[f]||m[f]||o;return r?i.a.createElement(b,c({ref:t},l,{components:r})):i.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,a=new Array(o);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 l=2;l1?arguments[1]:void 0,r),s=a>2?arguments[2]:void 0,l=void 0===s?r:i(s,r);l>c;)t[c++]=e;return t}},454:function(e,t,r){var n=r(28).f,i=Function.prototype,o=/^\s*function ([^ (]*)/;"name"in i||r(10)&&n(i,"name",{configurable:!0,get:function(){try{return(""+this).match(o)[1]}catch(e){return""}}})},455:function(e,t,r){"use strict";r(454);var n=r(0),i=r.n(n),o=r(450);t.a=function(e){var t=e.children,r=e.name;return i.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"},i.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",r||"page"," assumes the following:"),t)}},456:function(e,t,r){"use strict";var n=r(1),i=r(0),o=r.n(i),a=r(39),c=r(460),s=r(20),l=r.n(s);t.a=function(e){var t,r=e.to,s=e.href,u=r||s,p=Object(c.a)(u),m=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?o.a.createElement(a.b,Object(n.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(u),m.current=!0)},innerRef:function(e){var r,n;f&&e&&p&&(r=e,n=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(),n())}))}))).observe(r))},to:u})):o.a.createElement("a",Object(n.a)({},e,{href:u}))}},459:function(e,t,r){"use strict";var n=r(0),i=r.n(n),o=r(456),a=r(449),c=r.n(a);r(134);t.a=function(e){var t=e.children,r=e.className,n=e.badge,a=e.leftIcon,s=e.rightIcon,l=e.size,u=e.target,p=e.to,m=c()("jump-to","jump-to--"+l,r),f=i.a.createElement("div",{className:"jump-to--inner"},i.a.createElement("div",{className:"jump-to--inner-2"},a&&i.a.createElement("div",{className:"jump-to--left"},i.a.createElement("i",{className:"feather icon-"+a})),i.a.createElement("div",{className:"jump-to--main"},n?i.a.createElement("span",{className:"badge badge--primary badge--right"},n):"",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:m},f):i.a.createElement(o.a,{to:p,className:m},f)}},460: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/2737c3be.238ac8b3.js.LICENSE.txt b/2737c3be.d0d1bcdd.js.LICENSE.txt similarity index 100% rename from 2737c3be.238ac8b3.js.LICENSE.txt rename to 2737c3be.d0d1bcdd.js.LICENSE.txt diff --git a/27d7a36c.4f2ceaed.js b/27d7a36c.6719258b.js similarity index 90% rename from 27d7a36c.4f2ceaed.js rename to 27d7a36c.6719258b.js index 4c9cd89fc9..58d448c253 100644 --- a/27d7a36c.4f2ceaed.js +++ b/27d7a36c.6719258b.js @@ -1,2 +1,2 @@ -/*! For license information please see 27d7a36c.4f2ceaed.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[53],{205: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 d}));var r=n(1),a=n(9),c=(n(0),n(449)),o=n(456),i=(n(448),n(453)),l={last_modified_on:"2023-12-30",title:"Quickstart",description:"Learn how to quickly install Qovery on your Scaleway (SCW) account"},s={id:"getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart",title:"Quickstart",description:"Learn how to quickly install Qovery on your Scaleway (SCW) account",source:"@site/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart.md",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart",sidebar:"docs",previous:{title:"Managed By Qovery",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery"},next:{title:"Create Credentials",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/create-credentials"}},u=[{value:"Create a Kubernetes cluster",id:"create-a-kubernetes-cluster",children:[]},{value:"Attach Scaleway credentials",id:"attach-scaleway-credentials",children:[]},{value:"Install Qovery",id:"install-qovery",children:[]}],p={rightToc:u};function d(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,"Install Qovery on your ",Object(c.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.scaleway.com"}),"Scaleway")," account in less than 20 minutes. Qovery will create a Kubernetes cluster for you and manage it for you. To install Qovery on an existing Kubernetes cluster, please refer to the ",Object(c.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/"}),"dedicated documentation"),"."),Object(c.b)(i.a,{mdxType:"Assumptions"},Object(c.b)("ul",null,Object(c.b)("li",{parentName:"ul"},"You have an account and an ",Object(c.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/"}),"Organization")," on Qovery"),Object(c.b)("li",{parentName:"ul"},"You have an Scaleway account"))),Object(c.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(c.b)("ol",null,Object(c.b)("li",null,Object(c.b)("h2",{id:"create-a-kubernetes-cluster"},"Create a Kubernetes cluster"),Object(c.b)("p",null,"Now you can create your Kubernetes cluster. Follow this ",Object(c.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"guide")," to create your Kubernetes cluster."),Object(c.b)("p",{align:"center"},Object(c.b)("img",{src:"/img/install-qovery/common/add-cluster.jpg",alt:"Add Cluster"})),Object(c.b)("p",null,"Note that you can create multiple clusters on the same Scaleway account with different VPCs. You can also create multiple clusters on different Scaleway accounts. Qovery will manage them for you.")),Object(c.b)("li",null,Object(c.b)("h2",{id:"attach-scaleway-credentials"},"Attach Scaleway credentials"),Object(c.b)("p",null,"Follow this ",Object(c.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/create-credentials/"}),"guide")," to create your Scaleway credentials."),Object(c.b)("p",{align:"center"},Object(c.b)("img",{src:"/img/install-qovery/scaleway/create-credentials.jpg",alt:"Create Credentials"})),Object(c.b)("p",null,"Then attach your credentials to your cluster and click on ",Object(c.b)("inlineCode",{parentName:"p"},"Create"),". Then, click on ",Object(c.b)("inlineCode",{parentName:"p"},"Continue"),".")),Object(c.b)("li",null,Object(c.b)("h2",{id:"install-qovery"},"Install Qovery"),Object(c.b)("p",null,"Click on ",Object(c.b)("inlineCode",{parentName:"p"},"Create and Deploy")," to create the cluster and install Qovery on it."),Object(c.b)("p",null,"It will take up to 20 minutes to create the cluster, VPC and install Qovery on it. But you can already ",Object(c.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"configure your first application"),"."),Object(c.b)("p",null,"You should see your new cluster in the list of clusters."),Object(c.b)("p",{align:"center"},Object(c.b)("img",{src:"/img/install-qovery/common/list-clusters.jpg",alt:"Show clusters"}))))))}d.isMDXComponent=!0},447: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({}),u=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=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)}},y=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,c=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),y=r,b=p["".concat(o,".").concat(y)]||p[y]||d[y]||c;return n?a.a.createElement(b,i({ref:t},s,{components:n})):a.a.createElement(b,i({ref:t},s))}));function b(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 l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:r,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:a(l,n);s>i;)t[i++]=e;return t}},452:function(e,t,n){var r=n(28).f,a=Function.prototype,c=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(c)[1]}catch(e){return""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),c=n(448);t.a=function(e){var t=e.children,n=e.name;return a.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"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},455:function(e,t,n){"use strict";var r=n(459),a=n(51);function c(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(),c=t.length>0?t.join("="):void 0;c=void 0===c?null:decodeURIComponent(c),n(decodeURIComponent(a),c,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?[c(t,e),"[",r,"]"].join(""):[c(t,e),"[",c(r,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=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 c(r,t);if(Array.isArray(a)){var o=[];return a.slice().forEach((function(e){void 0!==e&&o.push(n(r,e,o.length))})),o.join("&")}return c(r,t)+"="+c(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),c=(n(447),n(455)),o=n.n(c);n(133);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),u=Object(r.useState)(null),p=u[0],d=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!c&&!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"),"."))}},459: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 27d7a36c.6719258b.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[53],{205: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 d}));var r=n(1),a=n(9),c=(n(0),n(451)),o=n(458),i=(n(450),n(455)),l={last_modified_on:"2023-12-30",title:"Quickstart",description:"Learn how to quickly install Qovery on your Scaleway (SCW) account"},s={id:"getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart",title:"Quickstart",description:"Learn how to quickly install Qovery on your Scaleway (SCW) account",source:"@site/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart.md",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart",sidebar:"docs",previous:{title:"Managed By Qovery",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery"},next:{title:"Create Credentials",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/create-credentials"}},u=[{value:"Create a Kubernetes cluster",id:"create-a-kubernetes-cluster",children:[]},{value:"Attach Scaleway credentials",id:"attach-scaleway-credentials",children:[]},{value:"Install Qovery",id:"install-qovery",children:[]}],p={rightToc:u};function d(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,"Install Qovery on your ",Object(c.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.scaleway.com"}),"Scaleway")," account in less than 20 minutes. Qovery will create a Kubernetes cluster for you and manage it for you. To install Qovery on an existing Kubernetes cluster, please refer to the ",Object(c.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/"}),"dedicated documentation"),"."),Object(c.b)(i.a,{mdxType:"Assumptions"},Object(c.b)("ul",null,Object(c.b)("li",{parentName:"ul"},"You have an account and an ",Object(c.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/"}),"Organization")," on Qovery"),Object(c.b)("li",{parentName:"ul"},"You have an Scaleway account"))),Object(c.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(c.b)("ol",null,Object(c.b)("li",null,Object(c.b)("h2",{id:"create-a-kubernetes-cluster"},"Create a Kubernetes cluster"),Object(c.b)("p",null,"Now you can create your Kubernetes cluster. Follow this ",Object(c.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"guide")," to create your Kubernetes cluster."),Object(c.b)("p",{align:"center"},Object(c.b)("img",{src:"/img/install-qovery/common/add-cluster.jpg",alt:"Add Cluster"})),Object(c.b)("p",null,"Note that you can create multiple clusters on the same Scaleway account with different VPCs. You can also create multiple clusters on different Scaleway accounts. Qovery will manage them for you.")),Object(c.b)("li",null,Object(c.b)("h2",{id:"attach-scaleway-credentials"},"Attach Scaleway credentials"),Object(c.b)("p",null,"Follow this ",Object(c.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/create-credentials/"}),"guide")," to create your Scaleway credentials."),Object(c.b)("p",{align:"center"},Object(c.b)("img",{src:"/img/install-qovery/scaleway/create-credentials.jpg",alt:"Create Credentials"})),Object(c.b)("p",null,"Then attach your credentials to your cluster and click on ",Object(c.b)("inlineCode",{parentName:"p"},"Create"),". Then, click on ",Object(c.b)("inlineCode",{parentName:"p"},"Continue"),".")),Object(c.b)("li",null,Object(c.b)("h2",{id:"install-qovery"},"Install Qovery"),Object(c.b)("p",null,"Click on ",Object(c.b)("inlineCode",{parentName:"p"},"Create and Deploy")," to create the cluster and install Qovery on it."),Object(c.b)("p",null,"It will take up to 20 minutes to create the cluster, VPC and install Qovery on it. But you can already ",Object(c.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/getting-started/deploy-your-first-application/"}),"configure your first application"),"."),Object(c.b)("p",null,"You should see your new cluster in the list of clusters."),Object(c.b)("p",{align:"center"},Object(c.b)("img",{src:"/img/install-qovery/common/list-clusters.jpg",alt:"Show clusters"}))))))}d.isMDXComponent=!0},449: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({}),u=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=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)}},y=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,c=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),y=r,b=p["".concat(o,".").concat(y)]||p[y]||d[y]||c;return n?a.a.createElement(b,i({ref:t},s,{components:n})):a.a.createElement(b,i({ref:t},s))}));function b(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 l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:r,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:a(l,n);s>i;)t[i++]=e;return t}},454:function(e,t,n){var r=n(28).f,a=Function.prototype,c=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(c)[1]}catch(e){return""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),c=n(450);t.a=function(e){var t=e.children,n=e.name;return a.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"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},457:function(e,t,n){"use strict";var r=n(461),a=n(51);function c(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(),c=t.length>0?t.join("="):void 0;c=void 0===c?null:decodeURIComponent(c),n(decodeURIComponent(a),c,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?[c(t,e),"[",r,"]"].join(""):[c(t,e),"[",c(r,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=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 c(r,t);if(Array.isArray(a)){var o=[];return a.slice().forEach((function(e){void 0!==e&&o.push(n(r,e,o.length))})),o.join("&")}return c(r,t)+"="+c(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),c=(n(449),n(457)),o=n.n(c);n(133);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),u=Object(r.useState)(null),p=u[0],d=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!c&&!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"),"."))}},461: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/27d7a36c.4f2ceaed.js.LICENSE.txt b/27d7a36c.6719258b.js.LICENSE.txt similarity index 100% rename from 27d7a36c.4f2ceaed.js.LICENSE.txt rename to 27d7a36c.6719258b.js.LICENSE.txt diff --git a/293.61cf0512.js b/295.8b05ee56.js similarity index 93% rename from 293.61cf0512.js rename to 295.8b05ee56.js index 7494648f02..620dbfc363 100644 --- a/293.61cf0512.js +++ b/295.8b05ee56.js @@ -1,2 +1,2 @@ -/*! For license information please see 293.61cf0512.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[293],{501:function(t,e,n){"use strict";var r,i=n(506);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)}}},503: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.ad4736cf.js b/40a919e7.7b75caa9.js similarity index 93% rename from 40a919e7.ad4736cf.js rename to 40a919e7.7b75caa9.js index 35e8336b78..3c7abfa1c4 100644 --- a/40a919e7.ad4736cf.js +++ b/40a919e7.7b75caa9.js @@ -1,2 +1,2 @@ -/*! For license information please see 40a919e7.ad4736cf.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 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(449)),c=n(456),i=(n(448),{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},447: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}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),c=n.n(o);n(133);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"),"."))}},459: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.7b75caa9.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 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(451)),c=n(458),i=(n(450),{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},449: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}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),c=n.n(o);n(133);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"),"."))}},461: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/40c64f54.2100e705.js.LICENSE.txt b/40a919e7.7b75caa9.js.LICENSE.txt similarity index 100% rename from 40c64f54.2100e705.js.LICENSE.txt rename to 40a919e7.7b75caa9.js.LICENSE.txt diff --git a/40c64f54.2100e705.js b/40c64f54.c68cc801.js similarity index 90% rename from 40c64f54.2100e705.js rename to 40c64f54.c68cc801.js index 2f5086b32f..fcbaada2aa 100644 --- a/40c64f54.2100e705.js +++ b/40c64f54.c68cc801.js @@ -1,2 +1,2 @@ -/*! For license information please see 40c64f54.2100e705.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 o})),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),c=n(9),a=(n(0),n(449)),i=n(456),o=(n(448),n(453),{last_modified_on:"2023-12-30",title:"Create Credentials",description:"Generate your Scaleway credentials to connect your Scaleway account to Qovery"}),l={id:"getting-started/install-qovery/scaleway/cluster-managed-by-qovery/create-credentials",title:"Create Credentials",description:"Generate your Scaleway credentials to connect your Scaleway account to Qovery",source:"@site/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/create-credentials.md",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/create-credentials",sidebar:"docs",previous:{title:"Quickstart",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart"},next:{title:"FAQ",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/faq"}},s=[{value:"Generate your Scaleway credentials",id:"generate-your-scaleway-credentials",children:[]}],u={rightToc:s};function p(e){var t=e.components,n=Object(c.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("h2",{id:"generate-your-scaleway-credentials"},"Generate your Scaleway credentials"),Object(a.b)(i.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(r.a)({parentName:"p"},{href:"https://console.scaleway.com"}),"Connect to your Scaleway console"))),Object(a.b)("li",null,Object(a.b)("p",null,"Go to ",Object(a.b)("inlineCode",{parentName:"p"},"IAM")),Object(a.b)("img",{src:"/img/scw-api-key/scw_IAM.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Go to ",Object(a.b)("inlineCode",{parentName:"p"},"Applications")),Object(a.b)("img",{src:"/img/scw-api-key/scw_applications.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Create a new application for your project"),Object(a.b)("img",{src:"/img/scw-api-key/scw_create_app.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Generate your new API key from your application view"),Object(a.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(a.b)("img",{src:"/img/scw-api-key/scw_create_key_2.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Save the generated ",Object(a.b)("inlineCode",{parentName:"p"},"access key id")," and ",Object(a.b)("inlineCode",{parentName:"p"},"secret access key"),"."),Object(a.b)("img",{src:"/img/scw-api-key/scw_creds.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Go to ",Object(a.b)("inlineCode",{parentName:"p"},"Policies")),Object(a.b)("img",{src:"/img/scw-api-key/scw_policies.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Create a new policy with ",Object(a.b)("inlineCode",{parentName:"p"},"Principal")," linked to the application you just created."),Object(a.b)("img",{src:"/img/scw-api-key/scw_create_policy.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Set the scope of the policy to your project"),Object(a.b)("img",{src:"/img/scw-api-key/scw_policy_scope.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Select the following rules for your policy"),Object(a.b)("ul",null,Object(a.b)("li",null,"Containers permissions",Object(a.b)("br",null),Object(a.b)("img",{src:"/img/scw-api-key/scw_perms_containers.png"})),Object(a.b)("li",null,"Network Service permissions",Object(a.b)("br",null),Object(a.b)("img",{src:"/img/scw-api-key/scw_perms_network.png"})),Object(a.b)("li",null,"Compute permissions",Object(a.b)("br",null),Object(a.b)("img",{src:"/img/scw-api-key/scw_perms_compute.png"})),Object(a.b)("li",null,"Storage permissions",Object(a.b)("br",null),Object(a.b)("img",{src:"/img/scw-api-key/scw_perms_storage.png"})),Object(a.b)("li",null,"VPC permissions",Object(a.b)("br",null),Object(a.b)("img",{src:"/img/scw-api-key/scw_perms_vpc.png"})))),Object(a.b)("li",null,Object(a.b)("p",null,"Create your policy"),Object(a.b)("img",{src:"/img/scw-api-key/scw_apply_policy.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Get your ",Object(a.b)("inlineCode",{parentName:"p"},"organization id")," in your ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://console.scaleway.com/organization/settings"}),"organization settings")),Object(a.b)("img",{src:"/img/scw-api-key/scw_organization_id.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Get your ",Object(a.b)("inlineCode",{parentName:"p"},"project id")," on your project dashboard"),Object(a.b)("img",{src:"/img/scw-api-key/scw_project_id.png"})))),Object(a.b)("p",null,"Well done!! You now have your Scaleway ",Object(a.b)("inlineCode",{parentName:"p"},"access key id"),", ",Object(a.b)("inlineCode",{parentName:"p"},"secret access key"),", ",Object(a.b)("inlineCode",{parentName:"p"},"organization_id")," and ",Object(a.b)("inlineCode",{parentName:"p"},"project id"),"; It is time to connect Qovery to your Scaleway account."))}p.isMDXComponent=!0},447:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function c(){for(var e=[],t=0;t=0||(c[n]=e[n]);return c}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(c[n]=e[n])}return c}var s=c.a.createContext({}),u=function(e){var t=c.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o({},t,{},e)),n},p=function(e){var t=u(e.components);return c.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return c.a.createElement(c.a.Fragment,{},t)}},y=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),y=r,m=p["".concat(i,".").concat(y)]||p[y]||b[y]||a;return n?c.a.createElement(m,o({ref:t},s,{components:n})):c.a.createElement(m,o({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]=y;var o={};for(var l in t)hasOwnProperty.call(t,l)&&(o[l]=t[l]);o.originalType=e,o.mdxType="string"==typeof e?e:r,i[1]=o;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:c(l,n);s>o;)t[o++]=e;return t}},452:function(e,t,n){var r=n(28).f,c=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in c||n(10)&&r(c,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),c=n.n(r),a=n(448);t.a=function(e){var t=e.children,n=e.name;return c.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"},c.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},455:function(e,t,n){"use strict";var r=n(459),c=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=c({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("="),c=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(c),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=c({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var c=e[r];if(void 0===c)return"";if(null===c)return a(r,t);if(Array.isArray(c)){var i=[];return c.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(c,t)})).filter((function(e){return e.length>0})).join("&"):""}},456:function(e,t,n){"use strict";var r=n(0),c=n.n(r),a=(n(447),n(455)),i=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,o="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+o+" failed",body:"The tutorial on:\n\n"+o+"\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 c.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&c.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",c.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",c.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&c.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",c.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},459: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 40c64f54.c68cc801.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[79],{231:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return o})),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),c=n(9),a=(n(0),n(451)),i=n(458),o=(n(450),n(455),{last_modified_on:"2023-12-30",title:"Create Credentials",description:"Generate your Scaleway credentials to connect your Scaleway account to Qovery"}),l={id:"getting-started/install-qovery/scaleway/cluster-managed-by-qovery/create-credentials",title:"Create Credentials",description:"Generate your Scaleway credentials to connect your Scaleway account to Qovery",source:"@site/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/create-credentials.md",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/create-credentials",sidebar:"docs",previous:{title:"Quickstart",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart"},next:{title:"FAQ",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/faq"}},s=[{value:"Generate your Scaleway credentials",id:"generate-your-scaleway-credentials",children:[]}],u={rightToc:s};function p(e){var t=e.components,n=Object(c.a)(e,["components"]);return Object(a.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("h2",{id:"generate-your-scaleway-credentials"},"Generate your Scaleway credentials"),Object(a.b)(i.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(r.a)({parentName:"p"},{href:"https://console.scaleway.com"}),"Connect to your Scaleway console"))),Object(a.b)("li",null,Object(a.b)("p",null,"Go to ",Object(a.b)("inlineCode",{parentName:"p"},"IAM")),Object(a.b)("img",{src:"/img/scw-api-key/scw_IAM.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Go to ",Object(a.b)("inlineCode",{parentName:"p"},"Applications")),Object(a.b)("img",{src:"/img/scw-api-key/scw_applications.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Create a new application for your project"),Object(a.b)("img",{src:"/img/scw-api-key/scw_create_app.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Generate your new API key from your application view"),Object(a.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(a.b)("img",{src:"/img/scw-api-key/scw_create_key_2.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Save the generated ",Object(a.b)("inlineCode",{parentName:"p"},"access key id")," and ",Object(a.b)("inlineCode",{parentName:"p"},"secret access key"),"."),Object(a.b)("img",{src:"/img/scw-api-key/scw_creds.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Go to ",Object(a.b)("inlineCode",{parentName:"p"},"Policies")),Object(a.b)("img",{src:"/img/scw-api-key/scw_policies.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Create a new policy with ",Object(a.b)("inlineCode",{parentName:"p"},"Principal")," linked to the application you just created."),Object(a.b)("img",{src:"/img/scw-api-key/scw_create_policy.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Set the scope of the policy to your project"),Object(a.b)("img",{src:"/img/scw-api-key/scw_policy_scope.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Select the following rules for your policy"),Object(a.b)("ul",null,Object(a.b)("li",null,"Containers permissions",Object(a.b)("br",null),Object(a.b)("img",{src:"/img/scw-api-key/scw_perms_containers.png"})),Object(a.b)("li",null,"Network Service permissions",Object(a.b)("br",null),Object(a.b)("img",{src:"/img/scw-api-key/scw_perms_network.png"})),Object(a.b)("li",null,"Compute permissions",Object(a.b)("br",null),Object(a.b)("img",{src:"/img/scw-api-key/scw_perms_compute.png"})),Object(a.b)("li",null,"Storage permissions",Object(a.b)("br",null),Object(a.b)("img",{src:"/img/scw-api-key/scw_perms_storage.png"})),Object(a.b)("li",null,"VPC permissions",Object(a.b)("br",null),Object(a.b)("img",{src:"/img/scw-api-key/scw_perms_vpc.png"})))),Object(a.b)("li",null,Object(a.b)("p",null,"Create your policy"),Object(a.b)("img",{src:"/img/scw-api-key/scw_apply_policy.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Get your ",Object(a.b)("inlineCode",{parentName:"p"},"organization id")," in your ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://console.scaleway.com/organization/settings"}),"organization settings")),Object(a.b)("img",{src:"/img/scw-api-key/scw_organization_id.png"})),Object(a.b)("li",null,Object(a.b)("p",null,"Get your ",Object(a.b)("inlineCode",{parentName:"p"},"project id")," on your project dashboard"),Object(a.b)("img",{src:"/img/scw-api-key/scw_project_id.png"})))),Object(a.b)("p",null,"Well done!! You now have your Scaleway ",Object(a.b)("inlineCode",{parentName:"p"},"access key id"),", ",Object(a.b)("inlineCode",{parentName:"p"},"secret access key"),", ",Object(a.b)("inlineCode",{parentName:"p"},"organization_id")," and ",Object(a.b)("inlineCode",{parentName:"p"},"project id"),"; It is time to connect Qovery to your Scaleway account."))}p.isMDXComponent=!0},449:function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function c(){for(var e=[],t=0;t=0||(c[n]=e[n]);return c}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(c[n]=e[n])}return c}var s=c.a.createContext({}),u=function(e){var t=c.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o({},t,{},e)),n},p=function(e){var t=u(e.components);return c.a.createElement(s.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return c.a.createElement(c.a.Fragment,{},t)}},y=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),y=r,m=p["".concat(i,".").concat(y)]||p[y]||b[y]||a;return n?c.a.createElement(m,o({ref:t},s,{components:n})):c.a.createElement(m,o({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]=y;var o={};for(var l in t)hasOwnProperty.call(t,l)&&(o[l]=t[l]);o.originalType=e,o.mdxType="string"==typeof e?e:r,i[1]=o;for(var s=2;s1?arguments[1]:void 0,n),l=i>2?arguments[2]:void 0,s=void 0===l?n:c(l,n);s>o;)t[o++]=e;return t}},454:function(e,t,n){var r=n(28).f,c=Function.prototype,a=/^\s*function ([^ (]*)/;"name"in c||n(10)&&r(c,"name",{configurable:!0,get:function(){try{return(""+this).match(a)[1]}catch(e){return""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),c=n.n(r),a=n(450);t.a=function(e){var t=e.children,n=e.name;return c.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"},c.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},457:function(e,t,n){"use strict";var r=n(461),c=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=c({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("="),c=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(c),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=c({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(r){var c=e[r];if(void 0===c)return"";if(null===c)return a(r,t);if(Array.isArray(c)){var i=[];return c.slice().forEach((function(e){void 0!==e&&i.push(n(r,e,i.length))})),i.join("&")}return a(r,t)+"="+a(c,t)})).filter((function(e){return e.length>0})).join("&"):""}},458:function(e,t,n){"use strict";var r=n(0),c=n.n(r),a=(n(449),n(457)),i=n.n(a);n(133);t.a=function(e){var t=e.children,n=e.headingDepth,a=e.hideFeedbackQuestion,o="undefined"!=typeof window?window.location:null,l={title:"Tutorial on "+o+" failed",body:"The tutorial on:\n\n"+o+"\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 c.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!p&&c.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",c.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",c.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==p&&c.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",c.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},461: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/40ec3bc1.9d9380f4.js.LICENSE.txt b/40c64f54.c68cc801.js.LICENSE.txt similarity index 100% rename from 40ec3bc1.9d9380f4.js.LICENSE.txt rename to 40c64f54.c68cc801.js.LICENSE.txt diff --git a/40ec3bc1.9d9380f4.js b/40ec3bc1.17e89e39.js similarity index 94% rename from 40ec3bc1.9d9380f4.js rename to 40ec3bc1.17e89e39.js index 5123f94fd9..1b98bf71c6 100644 --- a/40ec3bc1.9d9380f4.js +++ b/40ec3bc1.17e89e39.js @@ -1,2 +1,2 @@ -/*! For license information please see 40ec3bc1.9d9380f4.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[79],{231: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(449)),a=n(456),c=n(448),l=n(453),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 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 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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var o=n(0),r=n.n(o),i=n(448);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)}},455:function(e,t,n){"use strict";var o=n(459),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("&"):""}},456:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(447),n(455)),a=n.n(i);n(133);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"),"."))}},459: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.17e89e39.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 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(451)),a=n(458),c=n(450),l=n(455),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 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 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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var o=n(0),r=n.n(o),i=n(450);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)}},457:function(e,t,n){"use strict";var o=n(461),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("&"):""}},458:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(449),n(457)),a=n.n(i);n(133);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"),"."))}},461: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/4132998e.5d1865d5.js.LICENSE.txt b/40ec3bc1.17e89e39.js.LICENSE.txt similarity index 100% rename from 4132998e.5d1865d5.js.LICENSE.txt rename to 40ec3bc1.17e89e39.js.LICENSE.txt diff --git a/410a9ba0.aa343bb8.js b/410a9ba0.4fc1aae7.js similarity index 94% rename from 410a9ba0.aa343bb8.js rename to 410a9ba0.4fc1aae7.js index 0304cdfe22..1740def5a7 100644 --- a/410a9ba0.aa343bb8.js +++ b/410a9ba0.4fc1aae7.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[80],{232: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(449)),i=n(448),l=(n(461),n(453)),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},448:function(e,t,n){"use strict";n(450);var a=n(0),o=n.n(a),r=n(447),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)}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),o=n.n(a),r=n(448);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)}},461:function(e,t,n){"use strict";var a=n(1),o=(n(465),n(462),n(52),n(29),n(22),n(21),n(0)),r=n.n(o),i=n(469),l=n(447),c=n.n(l),s=n(455),u=n.n(s),b=n(468),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([[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 d}));var a=n(1),o=n(9),r=(n(0),n(451)),i=n(450),l=(n(463),n(455)),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},450:function(e,t,n){"use strict";n(452);var a=n(0),o=n.n(a),r=n(449),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)}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),o=n.n(a),r=n(450);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)}},463:function(e,t,n){"use strict";var a=n(1),o=(n(467),n(464),n(52),n(29),n(22),n(21),n(0)),r=n.n(o),i=n(471),l=n(449),c=n.n(l),s=n(457),u=n.n(s),b=n(470),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/4132998e.5d1865d5.js b/4132998e.20a57d2c.js similarity index 89% rename from 4132998e.5d1865d5.js rename to 4132998e.20a57d2c.js index 6ccebf8f22..76030d4bef 100644 --- a/4132998e.5d1865d5.js +++ b/4132998e.20a57d2c.js @@ -1,2 +1,2 @@ -/*! For license information please see 4132998e.5d1865d5.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[81],{233:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return s})),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(449)),c=r(457),i={last_modified_on:"2023-12-30",title:"AWS",sidebar_label:"hidden",hide_pagination:!0},s={id:"getting-started/install-qovery/aws",title:"AWS",description:"import Jump from '@site/src/components/Jump';",source:"@site/docs/getting-started/install-qovery/aws.md",permalink:"/docs/getting-started/install-qovery/aws",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Local",permalink:"/docs/getting-started/install-qovery/local"},next:{title:"Managed By Qovery",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery"}},u=[],l={rightToc:u};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,"It's a good choice. Choose your path:"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery",mdxType:"Jump"},"Cluster Managed by Qovery"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/aws/self-managed-cluster",mdxType:"Jump"},"Self-Managed Cluster"))}p.isMDXComponent=!0},447: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({}),l=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=l(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)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),d=n,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||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]=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:n,c[1]=i;for(var u=2;u0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):o.a.createElement("a",Object(n.a)({},e,{href:l}))}},457:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(454),c=r(447),i=r.n(c);r(134);t.a=function(e){var t=e.children,r=e.className,n=e.badge,c=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,f=i()("jump-to","jump-to--"+u,r),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"},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 l?a.a.createElement("a",{href:p,target:l,className:f},d):a.a.createElement(o.a,{to:p,className:f},d)}},458: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 4132998e.20a57d2c.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[82],{234:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return s})),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(451)),c=r(459),i={last_modified_on:"2023-12-30",title:"AWS",sidebar_label:"hidden",hide_pagination:!0},s={id:"getting-started/install-qovery/aws",title:"AWS",description:"import Jump from '@site/src/components/Jump';",source:"@site/docs/getting-started/install-qovery/aws.md",permalink:"/docs/getting-started/install-qovery/aws",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Local",permalink:"/docs/getting-started/install-qovery/local"},next:{title:"Managed By Qovery",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery"}},u=[],l={rightToc:u};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,"It's a good choice. Choose your path:"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery",mdxType:"Jump"},"Cluster Managed by Qovery"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/aws/self-managed-cluster",mdxType:"Jump"},"Self-Managed Cluster"))}p.isMDXComponent=!0},449: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({}),l=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=l(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)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),d=n,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||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]=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:n,c[1]=i;for(var u=2;u0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):o.a.createElement("a",Object(n.a)({},e,{href:l}))}},459:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(456),c=r(449),i=r.n(c);r(134);t.a=function(e){var t=e.children,r=e.className,n=e.badge,c=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,f=i()("jump-to","jump-to--"+u,r),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"},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 l?a.a.createElement("a",{href:p,target:l,className:f},d):a.a.createElement(o.a,{to:p,className:f},d)}},460: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/4354960d.e43d9003.js.LICENSE.txt b/4132998e.20a57d2c.js.LICENSE.txt similarity index 100% rename from 4354960d.e43d9003.js.LICENSE.txt rename to 4132998e.20a57d2c.js.LICENSE.txt diff --git a/4354960d.e43d9003.js b/4354960d.79e0cc9d.js similarity index 89% rename from 4354960d.e43d9003.js rename to 4354960d.79e0cc9d.js index 7d7a91d011..0d57aec8ab 100644 --- a/4354960d.e43d9003.js +++ b/4354960d.79e0cc9d.js @@ -1,2 +1,2 @@ -/*! For license information please see 4354960d.e43d9003.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 u})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return l}));var r=n(1),a=n(9),o=(n(0),n(449)),c=n(457),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:"FAQ",permalink:"/docs/getting-started/install-qovery/kubernetes/faq"},next:{title:"What's next?",permalink:"/docs/getting-started/whats-next"}},p=[{value:"Advanced",id:"advanced",children:[]}],s={rightToc:p};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,"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"))}l.isMDXComponent=!0},447: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 p=a.a.createContext({}),s=function(e){var t=a.a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},l=function(e){var t=s(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)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,p=u(e,["components","mdxType","originalType","parentName"]),l=s(n),f=r,m=l["".concat(c,".").concat(f)]||l[f]||d[f]||o;return n?a.a.createElement(m,i({ref:t},p,{components:n})):a.a.createElement(m,i({ref:t},p))}));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 p=2;p0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:s})):o.a.createElement("a",Object(r.a)({},e,{href:s}))}},457:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(454),c=n(447),i=n.n(c);n(134);t.a=function(e){var t=e.children,n=e.className,r=e.badge,c=e.leftIcon,u=e.rightIcon,p=e.size,s=e.target,l=e.to,d=i()("jump-to","jump-to--"+p,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 s?a.a.createElement("a",{href:l,target:s,className:d},f):a.a.createElement(o.a,{to:l,className:d},f)}},458: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.79e0cc9d.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 i})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return l}));var r=n(1),a=n(9),o=(n(0),n(451)),c=n(459),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:"FAQ",permalink:"/docs/getting-started/install-qovery/kubernetes/faq"},next:{title:"What's next?",permalink:"/docs/getting-started/whats-next"}},p=[{value:"Advanced",id:"advanced",children:[]}],s={rightToc:p};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,"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"))}l.isMDXComponent=!0},449: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 p=a.a.createContext({}),s=function(e){var t=a.a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i({},t,{},e)),n},l=function(e){var t=s(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)}},f=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,p=u(e,["components","mdxType","originalType","parentName"]),l=s(n),f=r,m=l["".concat(c,".").concat(f)]||l[f]||d[f]||o;return n?a.a.createElement(m,i({ref:t},p,{components:n})):a.a.createElement(m,i({ref:t},p))}));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 p=2;p0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:s})):o.a.createElement("a",Object(r.a)({},e,{href:s}))}},459:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(456),c=n(449),i=n.n(c);n(134);t.a=function(e){var t=e.children,n=e.className,r=e.badge,c=e.leftIcon,u=e.rightIcon,p=e.size,s=e.target,l=e.to,d=i()("jump-to","jump-to--"+p,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 s?a.a.createElement("a",{href:l,target:s,className:d},f):a.a.createElement(o.a,{to:l,className:d},f)}},460: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.d05c2bd9.js.LICENSE.txt b/4354960d.79e0cc9d.js.LICENSE.txt similarity index 100% rename from 44b423be.d05c2bd9.js.LICENSE.txt rename to 4354960d.79e0cc9d.js.LICENSE.txt diff --git a/44b423be.d05c2bd9.js b/44b423be.417f32f2.js similarity index 90% rename from 44b423be.d05c2bd9.js rename to 44b423be.417f32f2.js index be8a6c273f..56c3d31ba7 100644 --- a/44b423be.d05c2bd9.js +++ b/44b423be.417f32f2.js @@ -1,2 +1,2 @@ -/*! For license information please see 44b423be.d05c2bd9.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 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(449)),i=n(456),c=n(453),s=(n(448),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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.417f32f2.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 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(451)),i=n(458),c=n(455),s=(n(450),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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.f9265929.js.LICENSE.txt b/44b423be.417f32f2.js.LICENSE.txt similarity index 100% rename from 4592dbe6.f9265929.js.LICENSE.txt rename to 44b423be.417f32f2.js.LICENSE.txt diff --git a/4592dbe6.f9265929.js b/4592dbe6.17bd1ec9.js similarity index 92% rename from 4592dbe6.f9265929.js rename to 4592dbe6.17bd1ec9.js index 24f0f294cb..7f21b2665c 100644 --- a/4592dbe6.f9265929.js +++ b/4592dbe6.17bd1ec9.js @@ -1,2 +1,2 @@ -/*! For license information please see 4592dbe6.f9265929.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 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(449)),i=n(448),c=(n(453),n(457),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),c=n(458),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}))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(454),i=n(447),c=n.n(i);n(134);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)}},458: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.17bd1ec9.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[85],{237: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(451)),i=n(450),c=(n(455),n(459),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),c=n(460),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}))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(456),i=n(449),c=n.n(i);n(134);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)}},460: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/47a329cb.c1b47056.js.LICENSE.txt b/4592dbe6.17bd1ec9.js.LICENSE.txt similarity index 100% rename from 47a329cb.c1b47056.js.LICENSE.txt rename to 4592dbe6.17bd1ec9.js.LICENSE.txt diff --git a/47a329cb.c1b47056.js b/47a329cb.67f32ca4.js similarity index 84% rename from 47a329cb.c1b47056.js rename to 47a329cb.67f32ca4.js index 2162537280..10d4b1f63a 100644 --- a/47a329cb.c1b47056.js +++ b/47a329cb.67f32ca4.js @@ -1,2 +1,2 @@ -/*! For license information please see 47a329cb.c1b47056.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[85],{237: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(449)),i=(n(457),n(448),n(453),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},454:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(458),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}))}},457:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(454),i=n(447),c=n.n(i);n(134);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)}},458: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.67f32ca4.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 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(451)),i=(n(459),n(450),n(455),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},456:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(460),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}))}},459:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(456),i=n(449),c=n.n(i);n(134);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)}},460: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/48764d63.21ebf19d.js.LICENSE.txt b/47a329cb.67f32ca4.js.LICENSE.txt similarity index 100% rename from 48764d63.21ebf19d.js.LICENSE.txt rename to 47a329cb.67f32ca4.js.LICENSE.txt diff --git a/48764d63.21ebf19d.js b/48764d63.98bb0b7e.js similarity index 91% rename from 48764d63.21ebf19d.js rename to 48764d63.98bb0b7e.js index e351b24907..b94d042628 100644 --- a/48764d63.21ebf19d.js +++ b/48764d63.98bb0b7e.js @@ -1,2 +1,2 @@ -/*! For license information please see 48764d63.21ebf19d.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 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(449)),i=(n(456),n(453)),c=(n(448),{last_modified_on:"2024-06-11",$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:"Install Qovery on your Amazon Web Services account",permalink:"/guides/installation-guide/guide-amazon-web-services"}},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 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"}),"roadmap")),Object(a.b)("p",null,"Do you need any help? ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Reach us on our forum")))}p.isMDXComponent=!0},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(447),n(455)),i=n.n(a);n(133);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"),"."))}},459: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.98bb0b7e.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[87],{239: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(451)),i=(n(458),n(455)),c=(n(450),{last_modified_on:"2024-06-11",$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:"Install Qovery on your Amazon Web Services account",permalink:"/guides/installation-guide/guide-amazon-web-services"}},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 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"}),"roadmap")),Object(a.b)("p",null,"Do you need any help? ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Reach us on our forum")))}p.isMDXComponent=!0},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(449),n(457)),i=n.n(a);n(133);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"),"."))}},461: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/48dbd876.7d018c87.js.LICENSE.txt b/48764d63.98bb0b7e.js.LICENSE.txt similarity index 100% rename from 48dbd876.7d018c87.js.LICENSE.txt rename to 48764d63.98bb0b7e.js.LICENSE.txt diff --git a/48912b2c.a84d6624.js b/48912b2c.780b7645.js similarity index 51% rename from 48912b2c.a84d6624.js rename to 48912b2c.780b7645.js index 2f70a2eb73..a2263b6765 100644 --- a/48912b2c.a84d6624.js +++ b/48912b2c.780b7645.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[87],{239:function(n,t,u){"use strict";u.r(t);var r=u(0),c=u.n(r),e=u(496);t.default=function(){return c.a.createElement(e.a,{to:"/community/"})}},496: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([[88],{240:function(n,t,u){"use strict";u.r(t);var r=u(0),c=u.n(r),e=u(498);t.default=function(){return c.a.createElement(e.a,{to:"/community/"})}},498: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/48dbd876.7d018c87.js b/48dbd876.e15f6a03.js similarity index 91% rename from 48dbd876.7d018c87.js rename to 48dbd876.e15f6a03.js index 1a07d513dc..5ba28f28f1 100644 --- a/48dbd876.7d018c87.js +++ b/48dbd876.e15f6a03.js @@ -1,2 +1,2 @@ -/*! For license information please see 48dbd876.7d018c87.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[88],{240: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(449)),i=(n(456),n(448),n(453),{last_modified_on:"2024-04-12",title:"FAQ",description:"Frequently asked questions AWS infrastructure managed by Qovery"}),c={id:"getting-started/install-qovery/aws/cluster-managed-by-qovery/faq",title:"FAQ",description:"Frequently asked questions AWS infrastructure managed by Qovery",source:"@site/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/faq.md",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/faq",sidebar:"docs",previous:{title:"Infrastructure",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure"},next:{title:"Self-Managed Cluster",permalink:"/docs/getting-started/install-qovery/aws/self-managed-cluster"}},s=[{value:"How Qovery works on Managed AWS cluster",id:"how-qovery-works-on-managed-aws-cluster",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:[]}]}],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)("h2",{id:"how-qovery-works-on-managed-aws-cluster"},"How Qovery works on Managed AWS cluster"),Object(o.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(o.b)("p",null,Object(o.b)("a",Object(r.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 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(o.b)("h3",{id:"managed-services"},"Managed services"),Object(o.b)("p",null,"AWS provides managed services for ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/postgresql/"}),"PostgreSQL"),", ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/mysql/"}),"MySQL"),", ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/redis/"}),"Redis"),", ",Object(o.b)("a",Object(r.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(r.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 AWS account."),Object(o.b)("li",{parentName:"ul"},"Your configuration is encrypted on your AWS 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-aws"},"I don't find a region that is provided by AWS"),Object(o.b)("p",null,"We are probably testing the support of this region, please ",Object(o.b)("a",Object(r.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(r.a)({parentName:"p"},{href:"https://roadmap.qovery.com/roadmap"}),"here")," if you need this feature."))}l.isMDXComponent=!0},447: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},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)}},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"]),d=l(n),f=r,b=d["".concat(i,".").concat(f)]||d[f]||p[f]||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]=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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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),d=l[0],p=l[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!d&&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"==d&&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"),"."))}},459: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 48dbd876.e15f6a03.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[89],{241: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(451)),i=(n(458),n(450),n(455),{last_modified_on:"2024-04-12",title:"FAQ",description:"Frequently asked questions AWS infrastructure managed by Qovery"}),c={id:"getting-started/install-qovery/aws/cluster-managed-by-qovery/faq",title:"FAQ",description:"Frequently asked questions AWS infrastructure managed by Qovery",source:"@site/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/faq.md",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/faq",sidebar:"docs",previous:{title:"Infrastructure",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure"},next:{title:"Self-Managed Cluster",permalink:"/docs/getting-started/install-qovery/aws/self-managed-cluster"}},s=[{value:"How Qovery works on Managed AWS cluster",id:"how-qovery-works-on-managed-aws-cluster",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:[]}]}],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)("h2",{id:"how-qovery-works-on-managed-aws-cluster"},"How Qovery works on Managed AWS cluster"),Object(o.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(o.b)("p",null,Object(o.b)("a",Object(r.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 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(o.b)("h3",{id:"managed-services"},"Managed services"),Object(o.b)("p",null,"AWS provides managed services for ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/postgresql/"}),"PostgreSQL"),", ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/mysql/"}),"MySQL"),", ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/database/redis/"}),"Redis"),", ",Object(o.b)("a",Object(r.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(r.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 AWS account."),Object(o.b)("li",{parentName:"ul"},"Your configuration is encrypted on your AWS 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-aws"},"I don't find a region that is provided by AWS"),Object(o.b)("p",null,"We are probably testing the support of this region, please ",Object(o.b)("a",Object(r.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(r.a)({parentName:"p"},{href:"https://roadmap.qovery.com/roadmap"}),"here")," if you need this feature."))}l.isMDXComponent=!0},449: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},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)}},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"]),d=l(n),f=r,b=d["".concat(i,".").concat(f)]||d[f]||p[f]||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]=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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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),d=l[0],p=l[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!o&&!d&&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"==d&&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"),"."))}},461: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/498daee8.a81856b7.js.LICENSE.txt b/48dbd876.e15f6a03.js.LICENSE.txt similarity index 100% rename from 498daee8.a81856b7.js.LICENSE.txt rename to 48dbd876.e15f6a03.js.LICENSE.txt diff --git a/498daee8.a81856b7.js b/498daee8.670fad4c.js similarity index 92% rename from 498daee8.a81856b7.js rename to 498daee8.670fad4c.js index 8cebb0e937..37c48d83f5 100644 --- a/498daee8.a81856b7.js +++ b/498daee8.670fad4c.js @@ -1,2 +1,2 @@ -/*! For license information please see 498daee8.a81856b7.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[89],{241: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(449)),c=(r(456),r(453),r(448)),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 JupyterHub using Helm",permalink:"/guides/tutorial/deploy-jupyterhub-qovery"}},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},447: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)},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,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,m=p["".concat(c,".").concat(d)]||p[d]||b[d]||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]=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}},452: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""}}})},453:function(e,t,r){"use strict";r(452);var n=r(0),a=r.n(n),o=r(448);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)}},455:function(e,t,r){"use strict";var n=r(459),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("&"):""}},456:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(447),r(455)),c=r.n(o);r(133);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],b=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 b("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"),"."))}},459: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.670fad4c.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[90],{242: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(451)),c=(r(458),r(455),r(450)),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 JupyterHub using Helm",permalink:"/guides/tutorial/deploy-jupyterhub-qovery"}},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},449: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)},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,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,m=p["".concat(c,".").concat(d)]||p[d]||b[d]||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]=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}},454: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""}}})},455:function(e,t,r){"use strict";r(454);var n=r(0),a=r.n(n),o=r(450);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)}},457:function(e,t,r){"use strict";var n=r(461),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("&"):""}},458:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(449),r(457)),c=r.n(o);r(133);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],b=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 b("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"),"."))}},461: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/49a59b02.f80ead94.js.LICENSE.txt b/498daee8.670fad4c.js.LICENSE.txt similarity index 100% rename from 49a59b02.f80ead94.js.LICENSE.txt rename to 498daee8.670fad4c.js.LICENSE.txt diff --git a/49a59b02.f80ead94.js b/49a59b02.0c057b91.js similarity index 95% rename from 49a59b02.f80ead94.js rename to 49a59b02.0c057b91.js index d3ca29c70b..0155f4a522 100644 --- a/49a59b02.f80ead94.js +++ b/49a59b02.0c057b91.js @@ -1,2 +1,2 @@ -/*! For license information please see 49a59b02.f80ead94.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[90],{242: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(449)),a=n(456),l=n(448),c=n(453),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),i=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),i=(n(447),n(455)),a=n.n(i);n(133);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"),"."))}},459: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.0c057b91.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[91],{243: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(451)),a=n(458),l=n(450),c=n(455),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),i=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),i=(n(449),n(457)),a=n.n(i);n(133);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"),"."))}},461: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/4b542f80.79394608.js.LICENSE.txt b/49a59b02.0c057b91.js.LICENSE.txt similarity index 100% rename from 4b542f80.79394608.js.LICENSE.txt rename to 49a59b02.0c057b91.js.LICENSE.txt diff --git a/49d2885e.0b77fcc3.js b/49d2885e.0b77fcc3.js new file mode 100644 index 0000000000..8c8ee27572 --- /dev/null +++ b/49d2885e.0b77fcc3.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[92],{244:function(e){e.exports=JSON.parse('{"permalink":"/guides","page":1,"guidesPerPage":1,"totalPages":1,"totalCount":68,"previousPage":"/guides","nextPage":"/guides"}')}}]); \ No newline at end of file diff --git a/49d2885e.8431f712.js b/49d2885e.8431f712.js deleted file mode 100644 index 659f03a9ae..0000000000 --- a/49d2885e.8431f712.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[91],{243:function(e){e.exports=JSON.parse('{"permalink":"/guides","page":1,"guidesPerPage":1,"totalPages":1,"totalCount":67,"previousPage":"/guides","nextPage":"/guides"}')}}]); \ No newline at end of file diff --git a/49dea187.13b78e6e.js b/49dea187.48607317.js similarity index 72% rename from 49dea187.13b78e6e.js rename to 49dea187.48607317.js index bee5562816..cbdc105ddd 100644 --- a/49dea187.13b78e6e.js +++ b/49dea187.48607317.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[92],{244: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([[93],{245: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.cc4ce128.js b/4a111132.8937251f.js similarity index 74% rename from 4a111132.cc4ce128.js rename to 4a111132.8937251f.js index cccd77dec1..1f5a3ed2da 100644 --- a/4a111132.cc4ce128.js +++ b/4a111132.8937251f.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[93],{245: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([[94],{246: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/4b542f80.79394608.js b/4b542f80.57a683b6.js similarity index 90% rename from 4b542f80.79394608.js rename to 4b542f80.57a683b6.js index 6e22424f86..7477dafa34 100644 --- a/4b542f80.79394608.js +++ b/4b542f80.57a683b6.js @@ -1,2 +1,2 @@ -/*! For license information please see 4b542f80.79394608.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[94],{246: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 m}));var r=n(1),a=n(9),o=(n(0),n(449)),i=n(456),c=n(448),l=n(453),u=(n(457),{last_modified_on:"2024-04-10",$schema:"/.meta/.schemas/guides.json",title:"Monitor and reduce Kubernetes spend with Kubecost",description:"How to deploy Kubecost with Qovery",author_github:"https://github.com/jul-dan",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:"Monitor and reduce Kubernetes spend with Kubecost",description:"How to deploy Kubecost with Qovery",permalink:"/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost",readingTime:"3 min read",source:"@site/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Monitor and reduce Kubernetes spend with Kubecost",truncated:!1,prevItem:{title:"Migration",permalink:"/guides/advanced/migration"},nextItem:{title:"Monitoring",permalink:"/guides/advanced/monitoring"}},b=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],p={rightToc:b};function m(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)(l.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)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"In this tutorial, we will install Kubecost on a Qovery cluster to monitor the Kubernetes costs"),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"add-the-kubecost-helm-repository"},"Add the Kubecost helm repository"),Object(o.b)("p",null,"Add the Kubecost helm repository in your Qovery settings by following ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/helm-repository/"}),"this documentation")," with these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Repository name: ",Object(o.b)("inlineCode",{parentName:"li"},"Kubecost")),Object(o.b)("li",{parentName:"ul"},"Kind: ",Object(o.b)("inlineCode",{parentName:"li"},"HTTPS")),Object(o.b)("li",{parentName:"ul"},"Repository URL: ",Object(o.b)("inlineCode",{parentName:"li"},"https://kubecost.github.io/cost-analyzer/")))),Object(o.b)("li",null,Object(o.b)("h4",{id:"deploy-the-kubecost-helm-chart"},"Deploy the Kubecost helm chart"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If have a Kubecost token, first create a Qovery environment variable: "),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"variable: ",Object(o.b)("inlineCode",{parentName:"li"},"KUBECOST_TOKEN")),Object(o.b)("li",{parentName:"ul"},"value: ",Object(o.b)("inlineCode",{parentName:"li"},"")),Object(o.b)("li",{parentName:"ul"},"scope: ",Object(o.b)("inlineCode",{parentName:"li"},"Environment")),Object(o.b)("li",{parentName:"ul"},"Secret variable \u2714\ufe0f"))),Object(o.b)("p",null,"Deploy the Kubecost helm chart in your Qovery environment by following ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/"}),"this documentation")," with these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"General:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Application name: ",Object(o.b)("inlineCode",{parentName:"li"},"Kubecost")),Object(o.b)("li",{parentName:"ul"},"Source:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Helm source: ",Object(o.b)("inlineCode",{parentName:"li"},"Helm repository")),Object(o.b)("li",{parentName:"ul"},"Repository: ",Object(o.b)("inlineCode",{parentName:"li"},"Kubecost")," (the name given during the kubecost helm repository added in the previous step)"),Object(o.b)("li",{parentName:"ul"},"Chart name: ",Object(o.b)("inlineCode",{parentName:"li"},"cost-analyzer")),Object(o.b)("li",{parentName:"ul"},"Version: ",Object(o.b)("inlineCode",{parentName:"li"},"1.108.0")," (this guide works with the version 1.108.0 and that needs to be adapted if you use another version)"))),Object(o.b)("li",{parentName:"ul"},"Allow cluster-wide resources \u2714\ufe0f"))),Object(o.b)("li",{parentName:"ul"},"Values",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Values override as file:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"File source: ",Object(o.b)("inlineCode",{parentName:"li"},"Raw YAML")),Object(o.b)("li",{parentName:"ul"},"Raw YAML:")))))),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-yaml"}),"kubecostToken: qovery.env.KUBECOST_TOKEN #Used only if you have a Kubecost Token\n\n")),Object(o.b)("p",null,"Then click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create and Deploy"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"expose-kubecost"},"Expose Kubecost"),Object(o.b)("p",null,"Check the cost-analyzer service name in the deployment logs, example: ",Object(o.b)("inlineCode",{parentName:"p"},"helm-z325f0565-kubecost-cost-analyzer")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/monitor-and-reduce-kubernetes-spend-with-kubecost/service-name.png",alt:"Service name"})),Object(o.b)("p",null,"Go in your helm chart settings under the ",Object(o.b)("inlineCode",{parentName:"p"},"Networking")," section and add a new port by clicking on ",Object(o.b)("inlineCode",{parentName:"p"},"Add port"),", and set these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Service name: ",Object(o.b)("inlineCode",{parentName:"li"},"helm-z325f0565-kubecost-cost-analyzer")," (the service name taken from the deployment logs)"),Object(o.b)("li",{parentName:"ul"},"Service port: ",Object(o.b)("inlineCode",{parentName:"li"},"9090")),Object(o.b)("li",{parentName:"ul"},"Select protocol: ",Object(o.b)("inlineCode",{parentName:"li"},"HTTP")),Object(o.b)("li",{parentName:"ul"},"Port name: You can customize it or let the default port name.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/monitor-and-reduce-kubernetes-spend-with-kubecost/add-port.png",alt:"Add port"})),Object(o.b)("p",null,"Then click on Create and redeploy your helm in Qovery."),Object(o.b)("p",null,"A URL will be generated to access the Kubecost frontend application:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/monitor-and-reduce-kubernetes-spend-with-kubecost/link.png",alt:"Link"}))))),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"You now have Kubecost 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(r.a)({parentName:"p"},{href:"https://docs.kubecost.com/#getting-started"}),"https://docs.kubecost.com/#getting-started"),"."))}m.isMDXComponent=!0},447: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},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)}},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"]),b=s(n),m=r,d=b["".concat(i,".").concat(m)]||b[m]||p[m]||o;return n?a.a.createElement(d,c({ref:t},u,{components:n})):a.a.createElement(d,c({ref:t},u))}));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 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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},454:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(458),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,b=Object(c.a)(s),p=Object(a.useRef)(!1),m=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!m&&b&&window.docusaurus.prefetch(s),function(){m&&t&&t.disconnect()}}),[s,m,b]),s&&b?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var n,r;m&&e&&b&&(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}))}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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),b=s[0],p=s[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: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"),"."))}},457:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(454),i=n(447),c=n.n(i);n(134);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,b=e.to,p=c()("jump-to","jump-to--"+u,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 s?a.a.createElement("a",{href:b,target:s,className:p},m):a.a.createElement(o.a,{to:b,className:p},m)}},458:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},459: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 4b542f80.57a683b6.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 u})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return m}));var r=n(1),a=n(9),o=(n(0),n(451)),i=n(458),c=n(450),l=n(455),u=(n(459),{last_modified_on:"2024-04-10",$schema:"/.meta/.schemas/guides.json",title:"Monitor and reduce Kubernetes spend with Kubecost",description:"How to deploy Kubecost with Qovery",author_github:"https://github.com/jul-dan",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:"Monitor and reduce Kubernetes spend with Kubecost",description:"How to deploy Kubecost with Qovery",permalink:"/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost",readingTime:"3 min read",source:"@site/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Monitor and reduce Kubernetes spend with Kubecost",truncated:!1,prevItem:{title:"Migration",permalink:"/guides/advanced/migration"},nextItem:{title:"Monitoring",permalink:"/guides/advanced/monitoring"}},b=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],p={rightToc:b};function m(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)(l.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)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"In this tutorial, we will install Kubecost on a Qovery cluster to monitor the Kubernetes costs"),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"add-the-kubecost-helm-repository"},"Add the Kubecost helm repository"),Object(o.b)("p",null,"Add the Kubecost helm repository in your Qovery settings by following ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/helm-repository/"}),"this documentation")," with these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Repository name: ",Object(o.b)("inlineCode",{parentName:"li"},"Kubecost")),Object(o.b)("li",{parentName:"ul"},"Kind: ",Object(o.b)("inlineCode",{parentName:"li"},"HTTPS")),Object(o.b)("li",{parentName:"ul"},"Repository URL: ",Object(o.b)("inlineCode",{parentName:"li"},"https://kubecost.github.io/cost-analyzer/")))),Object(o.b)("li",null,Object(o.b)("h4",{id:"deploy-the-kubecost-helm-chart"},"Deploy the Kubecost helm chart"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If have a Kubecost token, first create a Qovery environment variable: "),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"variable: ",Object(o.b)("inlineCode",{parentName:"li"},"KUBECOST_TOKEN")),Object(o.b)("li",{parentName:"ul"},"value: ",Object(o.b)("inlineCode",{parentName:"li"},"")),Object(o.b)("li",{parentName:"ul"},"scope: ",Object(o.b)("inlineCode",{parentName:"li"},"Environment")),Object(o.b)("li",{parentName:"ul"},"Secret variable \u2714\ufe0f"))),Object(o.b)("p",null,"Deploy the Kubecost helm chart in your Qovery environment by following ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/"}),"this documentation")," with these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"General:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Application name: ",Object(o.b)("inlineCode",{parentName:"li"},"Kubecost")),Object(o.b)("li",{parentName:"ul"},"Source:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Helm source: ",Object(o.b)("inlineCode",{parentName:"li"},"Helm repository")),Object(o.b)("li",{parentName:"ul"},"Repository: ",Object(o.b)("inlineCode",{parentName:"li"},"Kubecost")," (the name given during the kubecost helm repository added in the previous step)"),Object(o.b)("li",{parentName:"ul"},"Chart name: ",Object(o.b)("inlineCode",{parentName:"li"},"cost-analyzer")),Object(o.b)("li",{parentName:"ul"},"Version: ",Object(o.b)("inlineCode",{parentName:"li"},"1.108.0")," (this guide works with the version 1.108.0 and that needs to be adapted if you use another version)"))),Object(o.b)("li",{parentName:"ul"},"Allow cluster-wide resources \u2714\ufe0f"))),Object(o.b)("li",{parentName:"ul"},"Values",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Values override as file:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"File source: ",Object(o.b)("inlineCode",{parentName:"li"},"Raw YAML")),Object(o.b)("li",{parentName:"ul"},"Raw YAML:")))))),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-yaml"}),"kubecostToken: qovery.env.KUBECOST_TOKEN #Used only if you have a Kubecost Token\n\n")),Object(o.b)("p",null,"Then click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create and Deploy"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"expose-kubecost"},"Expose Kubecost"),Object(o.b)("p",null,"Check the cost-analyzer service name in the deployment logs, example: ",Object(o.b)("inlineCode",{parentName:"p"},"helm-z325f0565-kubecost-cost-analyzer")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/monitor-and-reduce-kubernetes-spend-with-kubecost/service-name.png",alt:"Service name"})),Object(o.b)("p",null,"Go in your helm chart settings under the ",Object(o.b)("inlineCode",{parentName:"p"},"Networking")," section and add a new port by clicking on ",Object(o.b)("inlineCode",{parentName:"p"},"Add port"),", and set these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Service name: ",Object(o.b)("inlineCode",{parentName:"li"},"helm-z325f0565-kubecost-cost-analyzer")," (the service name taken from the deployment logs)"),Object(o.b)("li",{parentName:"ul"},"Service port: ",Object(o.b)("inlineCode",{parentName:"li"},"9090")),Object(o.b)("li",{parentName:"ul"},"Select protocol: ",Object(o.b)("inlineCode",{parentName:"li"},"HTTP")),Object(o.b)("li",{parentName:"ul"},"Port name: You can customize it or let the default port name.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/monitor-and-reduce-kubernetes-spend-with-kubecost/add-port.png",alt:"Add port"})),Object(o.b)("p",null,"Then click on Create and redeploy your helm in Qovery."),Object(o.b)("p",null,"A URL will be generated to access the Kubecost frontend application:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/monitor-and-reduce-kubernetes-spend-with-kubecost/link.png",alt:"Link"}))))),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"You now have Kubecost 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(r.a)({parentName:"p"},{href:"https://docs.kubecost.com/#getting-started"}),"https://docs.kubecost.com/#getting-started"),"."))}m.isMDXComponent=!0},449: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},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)}},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"]),b=s(n),m=r,d=b["".concat(i,".").concat(m)]||b[m]||p[m]||o;return n?a.a.createElement(d,c({ref:t},u,{components:n})):a.a.createElement(d,c({ref:t},u))}));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 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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},456:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(460),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,b=Object(c.a)(s),p=Object(a.useRef)(!1),m=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!m&&b&&window.docusaurus.prefetch(s),function(){m&&t&&t.disconnect()}}),[s,m,b]),s&&b?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var n,r;m&&e&&b&&(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}))}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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),b=s[0],p=s[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: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"),"."))}},459:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(456),i=n(449),c=n.n(i);n(134);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,b=e.to,p=c()("jump-to","jump-to--"+u,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 s?a.a.createElement("a",{href:b,target:s,className:p},m):a.a.createElement(o.a,{to:b,className:p},m)}},460:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},461: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/4dcdbf34.f7c5ad82.js.LICENSE.txt b/4b542f80.57a683b6.js.LICENSE.txt similarity index 100% rename from 4dcdbf34.f7c5ad82.js.LICENSE.txt rename to 4b542f80.57a683b6.js.LICENSE.txt diff --git a/4c0b3d74.f9e34734.js b/4c0b3d74.f9e34734.js new file mode 100644 index 0000000000..304f17bf18 --- /dev/null +++ b/4c0b3d74.f9e34734.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[96],{248:function(o){o.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"technology-qovery","name":"technology: qovery","count":42,"permalink":"/guides/tags/technology-qovery"}')}}]); \ No newline at end of file diff --git a/4c0b3d74.fea6427b.js b/4c0b3d74.fea6427b.js deleted file mode 100644 index 79177b05a0..0000000000 --- a/4c0b3d74.fea6427b.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[95],{247:function(o){o.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"technology-qovery","name":"technology: qovery","count":41,"permalink":"/guides/tags/technology-qovery"}')}}]); \ No newline at end of file diff --git a/4dcdbf34.f7c5ad82.js b/4dcdbf34.0d9faab0.js similarity index 95% rename from 4dcdbf34.f7c5ad82.js rename to 4dcdbf34.0d9faab0.js index 7c680ee644..448aecf703 100644 --- a/4dcdbf34.f7c5ad82.js +++ b/4dcdbf34.0d9faab0.js @@ -1,2 +1,2 @@ -/*! For license information please see 4dcdbf34.f7c5ad82.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[96],{248: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(449)),i=t(448),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},447: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.0d9faab0.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[97],{249: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(451)),i=t(450),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},449: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/4f6caeac.9ddda137.js.LICENSE.txt b/4dcdbf34.0d9faab0.js.LICENSE.txt similarity index 100% rename from 4f6caeac.9ddda137.js.LICENSE.txt rename to 4dcdbf34.0d9faab0.js.LICENSE.txt diff --git a/4f6caeac.9ddda137.js b/4f6caeac.d99dc2a0.js similarity index 98% rename from 4f6caeac.9ddda137.js rename to 4f6caeac.d99dc2a0.js index ae18a2f333..add9eaa354 100644 --- a/4f6caeac.9ddda137.js +++ b/4f6caeac.d99dc2a0.js @@ -1,2 +1,2 @@ -/*! For license information please see 4f6caeac.9ddda137.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[97],{249:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),a.d(t,"metadata",(function(){return s})),a.d(t,"rightToc",(function(){return o})),a.d(t,"default",(function(){return j}));var n=a(1),r=a(9),b=(a(0),a(449)),c=a(456),l=(a(457),a(448)),i=(a(453),{last_modified_on:"2024-07-30",title:"Service Advanced Settings",description:"Learn how to set advanced settings on your infrastructure with Qovery"}),s={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:"Affinity",id:"affinity",children:[]},{value:"Deployment strategy",id:"deployment-strategy",children:[]},{value:"Lifecycle Hooks",id:"lifecycle-hooks",children:[]}]},{value:"Network Settings",id:"network-settings",children:[]},{value:"Auto-scaling",id:"auto-scaling",children:[]},{value:"Job Settings",id:"job-settings",children:[]},{value:"Resources",id:"resources",children:[]},{value:"Security",id:"security",children:[]}],m={rightToc:o};function j(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(b.b)("wrapper",Object(n.a)({},m,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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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:"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)("h3",{id:"affinity"},"Affinity"),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)("h3",{id:"lifecycle-hooks"},"Lifecycle Hooks"),Object(b.b)("h4",{id:"deploymentlifecyclepost_start_exec_command"},"deployment.lifecycle.post_start_exec_command ",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 run a command after the application is started. The command should be a shell command or script."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"``")))),Object(b.b)("h4",{id:"deploymentlifecyclepre_stop_exec_command"},"deployment.lifecycle.pre_stop_exec_command ",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 run a command before the application is stopped. The command should be a shell command or script. Qovery requires the ",Object(b.b)("inlineCode",{parentName:"td"},"sh")," shell by default and sets a sleep of 15 seconds to let Nginx update its config. Avoiding error codes returned during a rolling update."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},'["/bin/sh", "-c", "sleep 15"]'))))),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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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:"networkingressadd_headers"},"network.ingress.add_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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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 additional headers to the outgoing response. The header values are 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)("h4",{id:"networkingressproxy_set_headers"},"network.ingress.proxy_set_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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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 additional headers to the incoming requests. The header values are 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)("h4",{id:"hpamemoryaverage_utilization_percent"},"hpa.memory.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 memory 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"},"null"))))),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:"resources"},"Resources"),Object(b.b)("h4",{id:"resourcesoverridelimitcpu_in_milli"},"resources.override.limit.cpu_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/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)(l.a,{type:"warning",mdxType:"Alert"},Object(b.b)("p",null,"Using overcommit on pod resources can lead to instability on your cluster and we strongly discourage it. Be careful when using this feature.")),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}),"Define the CPU overcommit (pod cpu limit) of the service."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"A service require more CPU at startup than during the running phase. You can reduce the configured CPU for the service and just increase the resources.override.limit.cpu_in_milli to reduce the resources used by the service at runtime"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"null")," (i.e. request = limit)")))),Object(b.b)("p",null,"This settings can be changed only if the advanced settings ",Object(b.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cluster-advanced-settings/#service"}),"allow_service_cpu_overcommit")," is set to ",Object(b.b)("inlineCode",{parentName:"p"},"true"),"."),Object(b.b)("h4",{id:"resourcesoverridelimitram_in_mib"},"resources.override.limit.ram_in_mib ",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)(l.a,{type:"warning",mdxType:"Alert"},Object(b.b)("p",null,"Using overcommit on pod resources can lead to instability on your cluster and we strongly discourage it. Be careful when using this feature.")),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}),"Define the memory overcommit (pod memory limit) of the service."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"A service require more memory at startup than during the running phase. You can reduce the configured memory for the service and just increase the resources.override.limit.ram_in_mib to reduce the resources used by the service at runtime"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"null")," (i.e. request = limit)")))),Object(b.b)("p",null,"This settings can be changed only if the advanced settings ",Object(b.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cluster-advanced-settings/#service"}),"allow_service_ram_overcommit")," is set to ",Object(b.b)("inlineCode",{parentName:"p"},"true"),"."),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}),"``")))),Object(b.b)("h4",{id:"securityautomount_service_account_token"},"security.automount_service_account_token ",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}),"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}),"Automount Kubernetes service account token to have access to Kubernetes API from pods"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"false"))))))}j.isMDXComponent=!0},447: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 s=r.a.createContext({}),o=function(e){var t=r.a.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):l({},t,{},e)),a},m=function(e){var t=o(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},j={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,b=e.originalType,c=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),m=o(a),p=n,d=m["".concat(c,".").concat(p)]||m[p]||j[p]||b;return a?r.a.createElement(d,l({ref:t},s,{components:a})):r.a.createElement(d,l({ref:t},s))}));function d(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var b=a.length,c=new Array(b);c[0]=p;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 s=2;s1?arguments[1]:void 0,a),i=c>2?arguments[2]:void 0,s=void 0===i?a:r(i,a);s>l;)t[l++]=e;return t}},452: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""}}})},453:function(e,t,a){"use strict";a(452);var n=a(0),r=a.n(n),b=a(448);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)}},454:function(e,t,a){"use strict";var n=a(1),r=a(0),b=a.n(r),c=a(39),l=a(458),i=a(20),s=a.n(i);t.a=function(e){var t,a=e.to,i=e.href,o=a||i,m=Object(l.a)(o),j=Object(r.useRef)(!1),p=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!p&&m&&window.docusaurus.prefetch(o),function(){p&&t&&t.disconnect()}}),[o,p,m]),o&&m?b.a.createElement(c.b,Object(n.a)({},e,{onMouseEnter:function(){j.current||(window.docusaurus.preload(o),j.current=!0)},innerRef:function(e){var a,n;p&&e&&m&&(a=e,n=function(){window.docusaurus.prefetch(o)},(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:o})):b.a.createElement("a",Object(n.a)({},e,{href:o}))}},455:function(e,t,a){"use strict";var n=a(459),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("&"):""}},456:function(e,t,a){"use strict";var n=a(0),r=a.n(n),b=(a(447),a(455)),c=a.n(b);a(133);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"},s="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(i),o=Object(n.useState)(null),m=o[0],j=o[1];return r.a.createElement("div",{className:"steps steps--h"+a},t,!b&&!m&&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:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==m&&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"),"."))}},457:function(e,t,a){"use strict";var n=a(0),r=a.n(n),b=a(454),c=a(447),l=a.n(c);a(134);t.a=function(e){var t=e.children,a=e.className,n=e.badge,c=e.leftIcon,i=e.rightIcon,s=e.size,o=e.target,m=e.to,j=l()("jump-to","jump-to--"+s,a),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"},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 o?r.a.createElement("a",{href:m,target:o,className:j},p):r.a.createElement(b.a,{to:m,className:j},p)}},458:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},459: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.d99dc2a0.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[98],{250:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),a.d(t,"metadata",(function(){return s})),a.d(t,"rightToc",(function(){return o})),a.d(t,"default",(function(){return j}));var n=a(1),r=a(9),b=(a(0),a(451)),c=a(458),l=(a(459),a(450)),i=(a(455),{last_modified_on:"2024-07-30",title:"Service Advanced Settings",description:"Learn how to set advanced settings on your infrastructure with Qovery"}),s={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:"Affinity",id:"affinity",children:[]},{value:"Deployment strategy",id:"deployment-strategy",children:[]},{value:"Lifecycle Hooks",id:"lifecycle-hooks",children:[]}]},{value:"Network Settings",id:"network-settings",children:[]},{value:"Auto-scaling",id:"auto-scaling",children:[]},{value:"Job Settings",id:"job-settings",children:[]},{value:"Resources",id:"resources",children:[]},{value:"Security",id:"security",children:[]}],m={rightToc:o};function j(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(b.b)("wrapper",Object(n.a)({},m,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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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:"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)("h3",{id:"affinity"},"Affinity"),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)("h3",{id:"lifecycle-hooks"},"Lifecycle Hooks"),Object(b.b)("h4",{id:"deploymentlifecyclepost_start_exec_command"},"deployment.lifecycle.post_start_exec_command ",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 run a command after the application is started. The command should be a shell command or script."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"``")))),Object(b.b)("h4",{id:"deploymentlifecyclepre_stop_exec_command"},"deployment.lifecycle.pre_stop_exec_command ",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 run a command before the application is stopped. The command should be a shell command or script. Qovery requires the ",Object(b.b)("inlineCode",{parentName:"td"},"sh")," shell by default and sets a sleep of 15 seconds to let Nginx update its config. Avoiding error codes returned during a rolling update."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},'["/bin/sh", "-c", "sleep 15"]'))))),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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.svg",alt:null}))," ",Object(b.b)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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:"networkingressadd_headers"},"network.ingress.add_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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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 additional headers to the outgoing response. The header values are 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)("h4",{id:"networkingressproxy_set_headers"},"network.ingress.proxy_set_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)("img",Object(n.a)({parentName:"h4"},{src:"/img/advanced_settings/helm.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 additional headers to the incoming requests. The header values are 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)("h4",{id:"hpamemoryaverage_utilization_percent"},"hpa.memory.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 memory 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"},"null"))))),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:"resources"},"Resources"),Object(b.b)("h4",{id:"resourcesoverridelimitcpu_in_milli"},"resources.override.limit.cpu_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/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)(l.a,{type:"warning",mdxType:"Alert"},Object(b.b)("p",null,"Using overcommit on pod resources can lead to instability on your cluster and we strongly discourage it. Be careful when using this feature.")),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}),"Define the CPU overcommit (pod cpu limit) of the service."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"A service require more CPU at startup than during the running phase. You can reduce the configured CPU for the service and just increase the resources.override.limit.cpu_in_milli to reduce the resources used by the service at runtime"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"null")," (i.e. request = limit)")))),Object(b.b)("p",null,"This settings can be changed only if the advanced settings ",Object(b.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cluster-advanced-settings/#service"}),"allow_service_cpu_overcommit")," is set to ",Object(b.b)("inlineCode",{parentName:"p"},"true"),"."),Object(b.b)("h4",{id:"resourcesoverridelimitram_in_mib"},"resources.override.limit.ram_in_mib ",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)(l.a,{type:"warning",mdxType:"Alert"},Object(b.b)("p",null,"Using overcommit on pod resources can lead to instability on your cluster and we strongly discourage it. Be careful when using this feature.")),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}),"Define the memory overcommit (pod memory limit) of the service."),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),"A service require more memory at startup than during the running phase. You can reduce the configured memory for the service and just increase the resources.override.limit.ram_in_mib to reduce the resources used by the service at runtime"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"null")," (i.e. request = limit)")))),Object(b.b)("p",null,"This settings can be changed only if the advanced settings ",Object(b.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/cluster-advanced-settings/#service"}),"allow_service_ram_overcommit")," is set to ",Object(b.b)("inlineCode",{parentName:"p"},"true"),"."),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}),"``")))),Object(b.b)("h4",{id:"securityautomount_service_account_token"},"security.automount_service_account_token ",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}),"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}),"Automount Kubernetes service account token to have access to Kubernetes API from pods"),Object(b.b)("td",Object(n.a)({parentName:"tr"},{align:null}),Object(b.b)("inlineCode",{parentName:"td"},"false"))))))}j.isMDXComponent=!0},449: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 s=r.a.createContext({}),o=function(e){var t=r.a.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):l({},t,{},e)),a},m=function(e){var t=o(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},j={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,b=e.originalType,c=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),m=o(a),p=n,d=m["".concat(c,".").concat(p)]||m[p]||j[p]||b;return a?r.a.createElement(d,l({ref:t},s,{components:a})):r.a.createElement(d,l({ref:t},s))}));function d(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var b=a.length,c=new Array(b);c[0]=p;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 s=2;s1?arguments[1]:void 0,a),i=c>2?arguments[2]:void 0,s=void 0===i?a:r(i,a);s>l;)t[l++]=e;return t}},454: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""}}})},455:function(e,t,a){"use strict";a(454);var n=a(0),r=a.n(n),b=a(450);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)}},456:function(e,t,a){"use strict";var n=a(1),r=a(0),b=a.n(r),c=a(39),l=a(460),i=a(20),s=a.n(i);t.a=function(e){var t,a=e.to,i=e.href,o=a||i,m=Object(l.a)(o),j=Object(r.useRef)(!1),p=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!p&&m&&window.docusaurus.prefetch(o),function(){p&&t&&t.disconnect()}}),[o,p,m]),o&&m?b.a.createElement(c.b,Object(n.a)({},e,{onMouseEnter:function(){j.current||(window.docusaurus.preload(o),j.current=!0)},innerRef:function(e){var a,n;p&&e&&m&&(a=e,n=function(){window.docusaurus.prefetch(o)},(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:o})):b.a.createElement("a",Object(n.a)({},e,{href:o}))}},457:function(e,t,a){"use strict";var n=a(461),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("&"):""}},458:function(e,t,a){"use strict";var n=a(0),r=a.n(n),b=(a(449),a(457)),c=a.n(b);a(133);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"},s="https://github.com/qovery/documentation/issues/new?"+c.a.stringify(i),o=Object(n.useState)(null),m=o[0],j=o[1];return r.a.createElement("div",{className:"steps steps--h"+a},t,!b&&!m&&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:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==m&&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"),"."))}},459:function(e,t,a){"use strict";var n=a(0),r=a.n(n),b=a(456),c=a(449),l=a.n(c);a(134);t.a=function(e){var t=e.children,a=e.className,n=e.badge,c=e.leftIcon,i=e.rightIcon,s=e.size,o=e.target,m=e.to,j=l()("jump-to","jump-to--"+s,a),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"},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 o?r.a.createElement("a",{href:m,target:o,className:j},p):r.a.createElement(b.a,{to:m,className:j},p)}},460:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},461: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.e6fcf89f.js.LICENSE.txt b/4f6caeac.d99dc2a0.js.LICENSE.txt similarity index 100% rename from 50bab564.e6fcf89f.js.LICENSE.txt rename to 4f6caeac.d99dc2a0.js.LICENSE.txt diff --git a/50bab564.e6fcf89f.js b/50bab564.1ae13bb6.js similarity index 96% rename from 50bab564.e6fcf89f.js rename to 50bab564.1ae13bb6.js index fb20777df3..02746448f7 100644 --- a/50bab564.e6fcf89f.js +++ b/50bab564.1ae13bb6.js @@ -1,2 +1,2 @@ -/*! For license information please see 50bab564.e6fcf89f.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[98],{250: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(449)),o=t(456),l=t(448),c=t(453),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 JupyterHub using Helm",permalink:"/guides/tutorial/deploy-jupyterhub-qovery"},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},447: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}},452: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""}}})},453:function(e,n,t){"use strict";t(452);var i=t(0),r=t.n(i),a=t(448);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)}},455:function(e,n,t){"use strict";var i=t(459),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("&"):""}},456:function(e,n,t){"use strict";var i=t(0),r=t.n(i),a=(t(447),t(455)),o=t.n(a);t(133);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"),"."))}},459: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.1ae13bb6.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[99],{251: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(451)),o=t(458),l=t(450),c=t(455),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 JupyterHub using Helm",permalink:"/guides/tutorial/deploy-jupyterhub-qovery"},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},449: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}},454: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""}}})},455:function(e,n,t){"use strict";t(454);var i=t(0),r=t.n(i),a=t(450);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)}},457:function(e,n,t){"use strict";var i=t(461),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("&"):""}},458:function(e,n,t){"use strict";var i=t(0),r=t.n(i),a=(t(449),t(457)),o=t.n(a);t(133);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"),"."))}},461: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/5385e737.5ab4e43b.js.LICENSE.txt b/50bab564.1ae13bb6.js.LICENSE.txt similarity index 100% rename from 5385e737.5ab4e43b.js.LICENSE.txt rename to 50bab564.1ae13bb6.js.LICENSE.txt diff --git a/5385e737.150c2aa9.js b/5385e737.150c2aa9.js new file mode 100644 index 0000000000..8924d1c37c --- /dev/null +++ b/5385e737.150c2aa9.js @@ -0,0 +1,2 @@ +/*! For license information please see 5385e737.150c2aa9.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[100],{252: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(451)),c=(r(458),r(455),r(450)),i={last_modified_on:"2023-12-30",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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},449: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}},454: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""}}})},455:function(e,t,r){"use strict";r(454);var a=r(0),n=r.n(a),o=r(450);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)}},457:function(e,t,r){"use strict";var a=r(461),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("&"):""}},458:function(e,t,r){"use strict";var a=r(0),n=r.n(a),o=(r(449),r(457)),c=r.n(o);r(133);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"),"."))}},461: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/543e268a.55f5eae9.js.LICENSE.txt b/5385e737.150c2aa9.js.LICENSE.txt similarity index 100% rename from 543e268a.55f5eae9.js.LICENSE.txt rename to 5385e737.150c2aa9.js.LICENSE.txt diff --git a/5385e737.5ab4e43b.js b/5385e737.5ab4e43b.js deleted file mode 100644 index 01d97191b2..0000000000 --- a/5385e737.5ab4e43b.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see 5385e737.5ab4e43b.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[99],{251: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(449)),c=(r(456),r(453),r(448)),i={last_modified_on:"2023-12-30",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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},447: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}},452: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""}}})},453:function(e,t,r){"use strict";r(452);var a=r(0),n=r.n(a),o=r(448);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)}},455:function(e,t,r){"use strict";var a=r(459),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("&"):""}},456:function(e,t,r){"use strict";var a=r(0),n=r.n(a),o=(r(447),r(455)),c=r.n(o);r(133);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"),"."))}},459: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/543e268a.55f5eae9.js b/543e268a.730b3e4a.js similarity index 88% rename from 543e268a.55f5eae9.js rename to 543e268a.730b3e4a.js index c6ba927de0..d54ad9cb4f 100644 --- a/543e268a.55f5eae9.js +++ b/543e268a.730b3e4a.js @@ -1,2 +1,2 @@ -/*! For license information please see 543e268a.55f5eae9.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[100],{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 p}));var r=n(1),a=n(9),o=(n(0),n(449)),c=n(457),i=(n(577),{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},447: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}))}},457:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(454),c=n(447),i=n.n(c);n(134);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)}},458:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},577:function(e,t,n){"use strict";n(0)}}]); \ No newline at end of file +/*! For license information please see 543e268a.730b3e4a.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[101],{253: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(451)),c=n(459),i=(n(579),{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},449: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}))}},459:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(456),c=n(449),i=n.n(c);n(134);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)}},460:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},579:function(e,t,n){"use strict";n(0)}}]); \ No newline at end of file diff --git a/54ad54c7.e7d1dbff.js.LICENSE.txt b/543e268a.730b3e4a.js.LICENSE.txt similarity index 100% rename from 54ad54c7.e7d1dbff.js.LICENSE.txt rename to 543e268a.730b3e4a.js.LICENSE.txt diff --git a/54ad54c7.e7d1dbff.js b/54ad54c7.53bb4f38.js similarity index 95% rename from 54ad54c7.e7d1dbff.js rename to 54ad54c7.53bb4f38.js index 64c4ec58bb..c2a419285e 100644 --- a/54ad54c7.e7d1dbff.js +++ b/54ad54c7.53bb4f38.js @@ -1,2 +1,2 @@ -/*! For license information please see 54ad54c7.e7d1dbff.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[101],{253: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),i=n(9),a=(n(0),n(449)),r=n(456),c=(n(457),n(448)),l=n(453),s={last_modified_on:"2024-07-03",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:"Deployment Restrictions",id:"deployment-restrictions",children:[]},{value:"Advanced Settings",id:"advanced-settings",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(i.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)(l.a,{name:"documentation",mdxType:"Assumptions"},Object(a.b)("p",null,"You have created an ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment"),".")),Object(a.b)("p",null,"A ",Object(a.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(a.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(a.b)("p",null,"Qovery allows you to create and deploy cronjobs from two different sources: Git Repository or Container Registry"),Object(a.b)("h2",{id:"deploying-from-a-git-repository"},"Deploying from a Git Repository"),Object(a.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(a.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(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/git-repository-access/"}),"GitHub Qovery Application")," (only for Github)."),Object(a.b)("h2",{id:"deploying-from-a-container-registry"},"Deploying from a Container Registry"),Object(a.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(a.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(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")),Object(a.b)("h2",{id:"create-a-cronjob"},"Create a Cronjob"),Object(a.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,'Go into the chosen environment and press the "New Service" button and then the "Create Cronjob" button'),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/environments/service_creation.png",alt:"Creation"}))),Object(a.b)("li",null,Object(a.b)("p",null,"Select the following fields:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Name: give a name to your applicaiton"),Object(a.b)("li",{parentName:"ul"},"Source: Chose between Git Repository or Container Registry, depending on the source location of your application")),Object(a.b)("p",null,"If you want to deploy a cronjob from a Git Repository you will have to select:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Git Repository: Select the git provider hosting your code (it can be hosted on GitHub, GitLab or Bitbucket). You can add a new git access by clicking on ",Object(a.b)("inlineCode",{parentName:"li"},"New git access"),"."),Object(a.b)("li",{parentName:"ul"},"Branch: Select branch that Qovery should use to deploy your code"),Object(a.b)("li",{parentName:"ul"},"Root Application Path: base folder in which the code resides in your repository"),Object(a.b)("li",{parentName:"ul"},"Build Mode: only Docker is supported")),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"A Dockerfile is necessary to build and deploy your job")),Object(a.b)("p",null,"If you want to deploy a cronjob from a Container Registry you will have to select:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Registry: select the container registry storing the image of your job. You can add a new container registry by clicking on ",Object(a.b)("inlineCode",{parentName:"li"},"New registry"),"."),Object(a.b)("li",{parentName:"ul"},"Image name: the name of the image to be deployed with this job (example: postgres)"),Object(a.b)("li",{parentName:"ul"},"Image tag: the tag of the image to be deployed with this job (example: 12)")),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"The tag 'latest' is not supported, please use a specific tag.")),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"}," Auto Deploy ")),Object(a.b)("p",null,"See the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"}," Extra labels/annotations (optional)")),Object(a.b)("p",null,"Add your extra annotation/label groups. See the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/labels-annotations/"}),"Add annotation/label group")," section for more information.")),Object(a.b)("li",null,"Specify the configuration of your job:",Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"CRON Schedule: specify a valid CRON expression (see ",Object(a.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(a.b)("li",{parentName:"ul"},"Timezone: select a valid timezone identifier. After being deployed, the job will be executed following the defined timezone. ",Object(a.b)("inlineCode",{parentName:"li"},"Etc/UTC")," is the default value."),Object(a.b)("li",{parentName:"ul"},"Image Entrypoint: the entrypoint to be used to launch your job (not mandatory)"),Object(a.b)("li",{parentName:"ul"},"CMD Arguments: the arguments to be passed to launch your application (not mandatory) separated with a space. Example: ",Object(a.b)("inlineCode",{parentName:"li"},'rails -h 0.0.0.0 -p 8080 string "complex arg"'),"."),Object(a.b)("li",{parentName:"ul"},"Number of restarts: Maximum number of restarts allowed in case of job failure (0 means no failure)"),Object(a.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(a.b)("li",{parentName:"ul"},"Port: Port used by Kubernetes to run readiness and liveliness probes checks. The port will not be exposed externally"))),Object(a.b)("li",null,"Within this section, you will need to define the resources to be assigned to your job at run time.",Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"vCPU: the vCPU assigned to each instance of your application. The default is 500m (0.5 vCPU)."),Object(a.b)("li",{parentName:"ul"},"RAM: the amount of RAM assigned to each instance of your application. The default is 512MB.")),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.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(a.b)("li",null,Object(a.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(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/job/variables.png",alt:"Input Variables"}))),Object(a.b)("li",null,Object(a.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(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/job/cronjob_recap.png",alt:"Recap"}))))),Object(a.b)("h2",{id:"deployment-management"},"Deployment Management"),Object(a.b)("p",null,"Have a look at the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/"}),"Deployment Management")," section for more information."),Object(a.b)("h2",{id:"force-run"},"Force Run"),Object(a.b)("p",null,"You can force the execution of a job independently its deployment status by:"),Object(a.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Select the job that you want to force")),Object(a.b)("li",null,Object(a.b)("p",null,"click on the ",Object(a.b)("inlineCode",{parentName:"p"},"Play")," button of the cronjob you want to force and select the ",Object(a.b)("inlineCode",{parentName:"p"},"Force Run")," option. Note: the same option is available on the service list as well")),Object(a.b)("li",null,Object(a.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(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.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(a.b)("h2",{id:"configuration"},"Configuration"),Object(a.b)("p",null,"Once created, you can access the configuration at any time via the Settings tab available on the service section"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/application/settings.png",alt:"Settings"})),Object(a.b)("p",null,"You can find below the description of each of the tabs available in this section"),Object(a.b)("h3",{id:"general"},"General"),Object(a.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(a.b)("h4",{id:"git-repository"},"Git Repository"),Object(a.b)("p",null,"If your job is built and deployed from a git repository, within this section you can:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Modify the git provider where your code is stored (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(a.b)("li",{parentName:"ul"},"Modify the branch that Qovery should use for deploying your code"),Object(a.b)("li",{parentName:"ul"},"Modify ",Object(a.b)("inlineCode",{parentName:"li"},"Root Application Path")," - base folder in which the application resides in your repository")),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Qovery supports mono repositories. ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/advanced/monorepository/"}),"See our advanced guide for more details."))),Object(a.b)(c.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"If your repository contains private submodules using SSH protocol, you will need to add a secret beginning with GIT",Object(a.b)("em",{parentName:"p"},"SSH_KEY"),", containing a private SSH key with access rights to your sumbodules repositories."),Object(a.b)("p",null,"Secret names examples:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITHUB"),Object(a.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITLAB"),Object(a.b)("li",{parentName:"ul"},"GIT_SSH_KEY_MYAPP"))),Object(a.b)("h4",{id:"container-registry"},"Container Registry"),Object(a.b)("p",null,"If your application is deployed from an image registry, within this section you can modify:"),Object(a.b)("ul",null,Object(a.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(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")," for more information."),Object(a.b)("li",{parentName:"ul"},"Image name: the name of the image to be deployed with this application (example: postgres)"),Object(a.b)("li",{parentName:"ul"},"Image tag: the tag of the image to be deployed with this application (example: 12)")),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"The tag 'latest' is not supported, please use a specific tag.")),Object(a.b)("h4",{id:"build-mode"},"Build Mode"),Object(a.b)("p",null,'This option is available only if you have selected "Git Repository" as source. Only Docker is supported'),Object(a.b)("p",null,"Qovery runs your application within the ",Object(a.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(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.docker.com/engine/reference/builder"}),"Dockerfile"),"."),Object(a.b)("p",null,"After creating a Dockerfile, specify the location of your Dockerfile in ",Object(a.b)("inlineCode",{parentName:"p"},"Dockefile path")," field."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"}," Auto Deploy ")),Object(a.b)("p",null,"See the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section."),Object(a.b)("h4",{id:"extra-labelsannotations"},"Extra labels/annotations"),Object(a.b)("p",null,"Add your extra annotation/label groups. See the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/labels-annotations/"}),"Add annotation/label group")," section for more information."),Object(a.b)("h3",{id:"job-configuration"},"JOB Configuration"),Object(a.b)("p",null,"You can modify here the configuration of your job:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"CRON Schedule: specify a valid CRON expression (see ",Object(a.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(a.b)("li",{parentName:"ul"},"Timezone: select a valid timezone identifier. After being deployed, the job will be executed following the defined timezone. ",Object(a.b)("inlineCode",{parentName:"li"},"Etc/UTC")," is the default value."),Object(a.b)("li",{parentName:"ul"},"Image Entrypoint: the entrypoint to be used to launch your job (not mandatory)"),Object(a.b)("li",{parentName:"ul"},"CMD Arguments: the arguments to be passed to launch your application (not mandatory) separated with a space. Example: ",Object(a.b)("inlineCode",{parentName:"li"},'rails -h 0.0.0.0 -p 8080 string "complex arg"'),"."),Object(a.b)("li",{parentName:"ul"},"Number of restarts: Maximum number of restarts allowed in case of job failure (0 means no failure)"),Object(a.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(a.b)("li",{parentName:"ul"},"Port: Port used by Kubernetes to run readiness and liveliness probes checks. The port will not be exposed externally")),Object(a.b)("h3",{id:"resources"},"Resources"),Object(a.b)("h4",{id:"cpu"},"CPU"),Object(a.b)("p",null,"To configure the number of CPUs that your job needs, adjust the setting in the ",Object(a.b)("inlineCode",{parentName:"p"},"Resources")," section."),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Default is 500m (0.5 vCPU). ")),Object(a.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(a.b)("h4",{id:"ram"},"RAM"),Object(a.b)("p",null,"To configure the amount of RAM that your app needs, adjust the setting in ",Object(a.b)("inlineCode",{parentName:"p"},"Resources")," section."),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Default is 512MB.")),Object(a.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(a.b)("h3",{id:"health-checks"},"Health Checks"),Object(a.b)("p",null,"To know more about how to configure your Liveness and Readiness probes, have a look at ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application-health-checks/"}),"the health-checks section")),Object(a.b)("h3",{id:"deployment-restrictions"},"Deployment Restrictions"),Object(a.b)("p",null,"This section allows to specify which changes on your repository should trigger an auto-deploy (if enabled). To know more about how to configure your Deployment Restrictions, have a look at the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/#filtering-commits-triggering-the-auto-deploy"}),"deployment restrictions section"),"."),Object(a.b)("h3",{id:"advanced-settings"},"Advanced Settings"),Object(a.b)("p",null,"You can further customize the service behaviour via the service advanced settings. Check ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/advanced-settings/"}),"this documentation")," to know more."),Object(a.b)("h2",{id:"environment-variable"},"Environment Variable"),Object(a.b)("p",null,"To learn how to set up environment variables in your projects and applications, navigate to ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"configuring Environment Variables")," section."),Object(a.b)("h2",{id:"secrets"},"Secrets"),Object(a.b)("p",null,"To learn how to set up secrets in your projects and applications, navigate to ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"configuring Secrets")," section."),Object(a.b)("h2",{id:"logs"},"Logs"),Object(a.b)("p",null,"To learn how to display your application logs, navigate to ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#live-logs"}),"logs section")),Object(a.b)("h2",{id:"clone"},"Clone"),Object(a.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(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/clone_service.png",alt:"Clone Service"})),Object(a.b)("p",null,"The target environment can be the same as the current environment or even another one in a completely different project."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"}," Important information ")),Object(a.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(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"same environment:",Object(a.b)("ul",{parentName:"li"},Object(a.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"))),Object(a.b)("li",{parentName:"ul"},"another environment:",Object(a.b)("ul",{parentName:"li"},Object(a.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"),Object(a.b)("li",{parentName:"ul"},"environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)"),Object(a.b)("li",{parentName:"ul"},"deployment pipeline: stage setup is not copied (since the target stage might not exist)"),Object(a.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(a.b)("p",null,"Please check the configuration of the new service before deploying it."),Object(a.b)("h2",{id:"delete-a-job"},"Delete a job"),Object(a.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Select the job you want to delete")),Object(a.b)("li",null,Object(a.b)("p",null,"In the overview, click on the ",Object(a.b)("inlineCode",{parentName:"p"},"3 dots")," button and remove the job. Note: the same option is available on the service list as well"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/application/app-1.png",alt:"Application"}))))))}d.isMDXComponent=!0},447: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):c({},t,{},e)),n},b=function(e){var t=u(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(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,r=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(n),d=o,h=b["".concat(r,".").concat(d)]||b[d]||p[d]||a;return n?i.a.createElement(h,c({ref:t},s,{components:n})):i.a.createElement(h,c({ref:t},s))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,r=new Array(a);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:o,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:i(l,n);s>c;)t[c++]=e;return t}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var o=n(0),i=n.n(o),a=n(448);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)}},454:function(e,t,n){"use strict";var o=n(1),i=n(0),a=n.n(i),r=n(39),c=n(458),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(i.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,b]),u&&b?a.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})):a.a.createElement("a",Object(o.a)({},e,{href:u}))}},455:function(e,t,n){"use strict";var o=n(459),i=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=i({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("="),i=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(i),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=i({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var i=e[o];if(void 0===i)return"";if(null===i)return a(o,t);if(Array.isArray(i)){var r=[];return i.slice().forEach((function(e){void 0!==e&&r.push(n(o,e,r.length))})),r.join("&")}return a(o,t)+"="+a(i,t)})).filter((function(e){return e.length>0})).join("&"):""}},456:function(e,t,n){"use strict";var o=n(0),i=n.n(o),a=(n(447),n(455)),r=n.n(a);n(133);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?"+r.a.stringify(l),u=Object(o.useState)(null),b=u[0],p=u[1];return i.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!b&&i.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",i.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",i.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&i.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",i.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},457:function(e,t,n){"use strict";var o=n(0),i=n.n(o),a=n(454),r=n(447),c=n.n(r);n(134);t.a=function(e){var t=e.children,n=e.className,o=e.badge,r=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,b=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"},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-"+(l||"chevron-right")+" arrow"}))));return u?i.a.createElement("a",{href:b,target:u,className:p},d):i.a.createElement(a.a,{to:b,className:p},d)}},458:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},459: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.53bb4f38.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[102],{254: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),i=n(9),a=(n(0),n(451)),r=n(458),c=(n(459),n(450)),l=n(455),s={last_modified_on:"2024-07-03",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:"Deployment Restrictions",id:"deployment-restrictions",children:[]},{value:"Advanced Settings",id:"advanced-settings",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(i.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)(l.a,{name:"documentation",mdxType:"Assumptions"},Object(a.b)("p",null,"You have created an ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment"),".")),Object(a.b)("p",null,"A ",Object(a.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(a.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(a.b)("p",null,"Qovery allows you to create and deploy cronjobs from two different sources: Git Repository or Container Registry"),Object(a.b)("h2",{id:"deploying-from-a-git-repository"},"Deploying from a Git Repository"),Object(a.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(a.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(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/git-repository-access/"}),"GitHub Qovery Application")," (only for Github)."),Object(a.b)("h2",{id:"deploying-from-a-container-registry"},"Deploying from a Container Registry"),Object(a.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(a.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(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")),Object(a.b)("h2",{id:"create-a-cronjob"},"Create a Cronjob"),Object(a.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,'Go into the chosen environment and press the "New Service" button and then the "Create Cronjob" button'),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/environments/service_creation.png",alt:"Creation"}))),Object(a.b)("li",null,Object(a.b)("p",null,"Select the following fields:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Name: give a name to your applicaiton"),Object(a.b)("li",{parentName:"ul"},"Source: Chose between Git Repository or Container Registry, depending on the source location of your application")),Object(a.b)("p",null,"If you want to deploy a cronjob from a Git Repository you will have to select:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Git Repository: Select the git provider hosting your code (it can be hosted on GitHub, GitLab or Bitbucket). You can add a new git access by clicking on ",Object(a.b)("inlineCode",{parentName:"li"},"New git access"),"."),Object(a.b)("li",{parentName:"ul"},"Branch: Select branch that Qovery should use to deploy your code"),Object(a.b)("li",{parentName:"ul"},"Root Application Path: base folder in which the code resides in your repository"),Object(a.b)("li",{parentName:"ul"},"Build Mode: only Docker is supported")),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"A Dockerfile is necessary to build and deploy your job")),Object(a.b)("p",null,"If you want to deploy a cronjob from a Container Registry you will have to select:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Registry: select the container registry storing the image of your job. You can add a new container registry by clicking on ",Object(a.b)("inlineCode",{parentName:"li"},"New registry"),"."),Object(a.b)("li",{parentName:"ul"},"Image name: the name of the image to be deployed with this job (example: postgres)"),Object(a.b)("li",{parentName:"ul"},"Image tag: the tag of the image to be deployed with this job (example: 12)")),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"The tag 'latest' is not supported, please use a specific tag.")),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"}," Auto Deploy ")),Object(a.b)("p",null,"See the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"}," Extra labels/annotations (optional)")),Object(a.b)("p",null,"Add your extra annotation/label groups. See the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/labels-annotations/"}),"Add annotation/label group")," section for more information.")),Object(a.b)("li",null,"Specify the configuration of your job:",Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"CRON Schedule: specify a valid CRON expression (see ",Object(a.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(a.b)("li",{parentName:"ul"},"Timezone: select a valid timezone identifier. After being deployed, the job will be executed following the defined timezone. ",Object(a.b)("inlineCode",{parentName:"li"},"Etc/UTC")," is the default value."),Object(a.b)("li",{parentName:"ul"},"Image Entrypoint: the entrypoint to be used to launch your job (not mandatory)"),Object(a.b)("li",{parentName:"ul"},"CMD Arguments: the arguments to be passed to launch your application (not mandatory) separated with a space. Example: ",Object(a.b)("inlineCode",{parentName:"li"},'rails -h 0.0.0.0 -p 8080 string "complex arg"'),"."),Object(a.b)("li",{parentName:"ul"},"Number of restarts: Maximum number of restarts allowed in case of job failure (0 means no failure)"),Object(a.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(a.b)("li",{parentName:"ul"},"Port: Port used by Kubernetes to run readiness and liveliness probes checks. The port will not be exposed externally"))),Object(a.b)("li",null,"Within this section, you will need to define the resources to be assigned to your job at run time.",Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"vCPU: the vCPU assigned to each instance of your application. The default is 500m (0.5 vCPU)."),Object(a.b)("li",{parentName:"ul"},"RAM: the amount of RAM assigned to each instance of your application. The default is 512MB.")),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.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(a.b)("li",null,Object(a.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(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/job/variables.png",alt:"Input Variables"}))),Object(a.b)("li",null,Object(a.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(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/job/cronjob_recap.png",alt:"Recap"}))))),Object(a.b)("h2",{id:"deployment-management"},"Deployment Management"),Object(a.b)("p",null,"Have a look at the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/"}),"Deployment Management")," section for more information."),Object(a.b)("h2",{id:"force-run"},"Force Run"),Object(a.b)("p",null,"You can force the execution of a job independently its deployment status by:"),Object(a.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Select the job that you want to force")),Object(a.b)("li",null,Object(a.b)("p",null,"click on the ",Object(a.b)("inlineCode",{parentName:"p"},"Play")," button of the cronjob you want to force and select the ",Object(a.b)("inlineCode",{parentName:"p"},"Force Run")," option. Note: the same option is available on the service list as well")),Object(a.b)("li",null,Object(a.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(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.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(a.b)("h2",{id:"configuration"},"Configuration"),Object(a.b)("p",null,"Once created, you can access the configuration at any time via the Settings tab available on the service section"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/application/settings.png",alt:"Settings"})),Object(a.b)("p",null,"You can find below the description of each of the tabs available in this section"),Object(a.b)("h3",{id:"general"},"General"),Object(a.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(a.b)("h4",{id:"git-repository"},"Git Repository"),Object(a.b)("p",null,"If your job is built and deployed from a git repository, within this section you can:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Modify the git provider where your code is stored (it can be hosted on GitHub, GitLab or Bitbucket)."),Object(a.b)("li",{parentName:"ul"},"Modify the branch that Qovery should use for deploying your code"),Object(a.b)("li",{parentName:"ul"},"Modify ",Object(a.b)("inlineCode",{parentName:"li"},"Root Application Path")," - base folder in which the application resides in your repository")),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Qovery supports mono repositories. ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/guides/advanced/monorepository/"}),"See our advanced guide for more details."))),Object(a.b)(c.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"If your repository contains private submodules using SSH protocol, you will need to add a secret beginning with GIT",Object(a.b)("em",{parentName:"p"},"SSH_KEY"),", containing a private SSH key with access rights to your sumbodules repositories."),Object(a.b)("p",null,"Secret names examples:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITHUB"),Object(a.b)("li",{parentName:"ul"},"GIT_SSH_KEY_GITLAB"),Object(a.b)("li",{parentName:"ul"},"GIT_SSH_KEY_MYAPP"))),Object(a.b)("h4",{id:"container-registry"},"Container Registry"),Object(a.b)("p",null,"If your application is deployed from an image registry, within this section you can modify:"),Object(a.b)("ul",null,Object(a.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(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")," for more information."),Object(a.b)("li",{parentName:"ul"},"Image name: the name of the image to be deployed with this application (example: postgres)"),Object(a.b)("li",{parentName:"ul"},"Image tag: the tag of the image to be deployed with this application (example: 12)")),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"The tag 'latest' is not supported, please use a specific tag.")),Object(a.b)("h4",{id:"build-mode"},"Build Mode"),Object(a.b)("p",null,'This option is available only if you have selected "Git Repository" as source. Only Docker is supported'),Object(a.b)("p",null,"Qovery runs your application within the ",Object(a.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(a.b)("a",Object(o.a)({parentName:"p"},{href:"https://docs.docker.com/engine/reference/builder"}),"Dockerfile"),"."),Object(a.b)("p",null,"After creating a Dockerfile, specify the location of your Dockerfile in ",Object(a.b)("inlineCode",{parentName:"p"},"Dockefile path")," field."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"}," Auto Deploy ")),Object(a.b)("p",null,"See the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"Deploying with auto-deploy feature")," section."),Object(a.b)("h4",{id:"extra-labelsannotations"},"Extra labels/annotations"),Object(a.b)("p",null,"Add your extra annotation/label groups. See the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/labels-annotations/"}),"Add annotation/label group")," section for more information."),Object(a.b)("h3",{id:"job-configuration"},"JOB Configuration"),Object(a.b)("p",null,"You can modify here the configuration of your job:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"CRON Schedule: specify a valid CRON expression (see ",Object(a.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(a.b)("li",{parentName:"ul"},"Timezone: select a valid timezone identifier. After being deployed, the job will be executed following the defined timezone. ",Object(a.b)("inlineCode",{parentName:"li"},"Etc/UTC")," is the default value."),Object(a.b)("li",{parentName:"ul"},"Image Entrypoint: the entrypoint to be used to launch your job (not mandatory)"),Object(a.b)("li",{parentName:"ul"},"CMD Arguments: the arguments to be passed to launch your application (not mandatory) separated with a space. Example: ",Object(a.b)("inlineCode",{parentName:"li"},'rails -h 0.0.0.0 -p 8080 string "complex arg"'),"."),Object(a.b)("li",{parentName:"ul"},"Number of restarts: Maximum number of restarts allowed in case of job failure (0 means no failure)"),Object(a.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(a.b)("li",{parentName:"ul"},"Port: Port used by Kubernetes to run readiness and liveliness probes checks. The port will not be exposed externally")),Object(a.b)("h3",{id:"resources"},"Resources"),Object(a.b)("h4",{id:"cpu"},"CPU"),Object(a.b)("p",null,"To configure the number of CPUs that your job needs, adjust the setting in the ",Object(a.b)("inlineCode",{parentName:"p"},"Resources")," section."),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Default is 500m (0.5 vCPU). ")),Object(a.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(a.b)("h4",{id:"ram"},"RAM"),Object(a.b)("p",null,"To configure the amount of RAM that your app needs, adjust the setting in ",Object(a.b)("inlineCode",{parentName:"p"},"Resources")," section."),Object(a.b)(c.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"Default is 512MB.")),Object(a.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(a.b)("h3",{id:"health-checks"},"Health Checks"),Object(a.b)("p",null,"To know more about how to configure your Liveness and Readiness probes, have a look at ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/application-health-checks/"}),"the health-checks section")),Object(a.b)("h3",{id:"deployment-restrictions"},"Deployment Restrictions"),Object(a.b)("p",null,"This section allows to specify which changes on your repository should trigger an auto-deploy (if enabled). To know more about how to configure your Deployment Restrictions, have a look at the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/#filtering-commits-triggering-the-auto-deploy"}),"deployment restrictions section"),"."),Object(a.b)("h3",{id:"advanced-settings"},"Advanced Settings"),Object(a.b)("p",null,"You can further customize the service behaviour via the service advanced settings. Check ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/advanced-settings/"}),"this documentation")," to know more."),Object(a.b)("h2",{id:"environment-variable"},"Environment Variable"),Object(a.b)("p",null,"To learn how to set up environment variables in your projects and applications, navigate to ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"configuring Environment Variables")," section."),Object(a.b)("h2",{id:"secrets"},"Secrets"),Object(a.b)("p",null,"To learn how to set up secrets in your projects and applications, navigate to ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"configuring Secrets")," section."),Object(a.b)("h2",{id:"logs"},"Logs"),Object(a.b)("p",null,"To learn how to display your application logs, navigate to ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#live-logs"}),"logs section")),Object(a.b)("h2",{id:"clone"},"Clone"),Object(a.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(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/clone_service.png",alt:"Clone Service"})),Object(a.b)("p",null,"The target environment can be the same as the current environment or even another one in a completely different project."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"}," Important information ")),Object(a.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(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"same environment:",Object(a.b)("ul",{parentName:"li"},Object(a.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"))),Object(a.b)("li",{parentName:"ul"},"another environment:",Object(a.b)("ul",{parentName:"li"},Object(a.b)("li",{parentName:"ul"},"custom domain: this setup is not copied into the new service (to avoid collision)"),Object(a.b)("li",{parentName:"ul"},"environment variable: aliases defined on environment variables are not copied (since the aliased env var might not exist)"),Object(a.b)("li",{parentName:"ul"},"deployment pipeline: stage setup is not copied (since the target stage might not exist)"),Object(a.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(a.b)("p",null,"Please check the configuration of the new service before deploying it."),Object(a.b)("h2",{id:"delete-a-job"},"Delete a job"),Object(a.b)(r.a,{headingDepth:3,mdxType:"Steps"},Object(a.b)("ol",null,Object(a.b)("li",null,Object(a.b)("p",null,"Select the job you want to delete")),Object(a.b)("li",null,Object(a.b)("p",null,"In the overview, click on the ",Object(a.b)("inlineCode",{parentName:"p"},"3 dots")," button and remove the job. Note: the same option is available on the service list as well"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/configuration/application/app-1.png",alt:"Application"}))))))}d.isMDXComponent=!0},449: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):c({},t,{},e)),n},b=function(e){var t=u(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(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,r=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(n),d=o,h=b["".concat(r,".").concat(d)]||b[d]||p[d]||a;return n?i.a.createElement(h,c({ref:t},s,{components:n})):i.a.createElement(h,c({ref:t},s))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,r=new Array(a);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:o,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:i(l,n);s>c;)t[c++]=e;return t}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var o=n(0),i=n.n(o),a=n(450);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)}},456:function(e,t,n){"use strict";var o=n(1),i=n(0),a=n.n(i),r=n(39),c=n(460),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(i.useRef)(!1),d=s.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!d&&b&&window.docusaurus.prefetch(u),function(){d&&t&&t.disconnect()}}),[u,d,b]),u&&b?a.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})):a.a.createElement("a",Object(o.a)({},e,{href:u}))}},457:function(e,t,n){"use strict";var o=n(461),i=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=i({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("="),i=t.shift(),a=t.length>0?t.join("="):void 0;a=void 0===a?null:decodeURIComponent(a),n(decodeURIComponent(i),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=i({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(o){var i=e[o];if(void 0===i)return"";if(null===i)return a(o,t);if(Array.isArray(i)){var r=[];return i.slice().forEach((function(e){void 0!==e&&r.push(n(o,e,r.length))})),r.join("&")}return a(o,t)+"="+a(i,t)})).filter((function(e){return e.length>0})).join("&"):""}},458:function(e,t,n){"use strict";var o=n(0),i=n.n(o),a=(n(449),n(457)),r=n.n(a);n(133);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?"+r.a.stringify(l),u=Object(o.useState)(null),b=u[0],p=u[1];return i.a.createElement("div",{className:"steps steps--h"+n},t,!a&&!b&&i.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",i.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return p("yes")}},"Yes"),"\xa0\xa0",i.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&i.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",i.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},459:function(e,t,n){"use strict";var o=n(0),i=n.n(o),a=n(456),r=n(449),c=n.n(r);n(134);t.a=function(e){var t=e.children,n=e.className,o=e.badge,r=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,b=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"},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-"+(l||"chevron-right")+" arrow"}))));return u?i.a.createElement("a",{href:b,target:u,className:p},d):i.a.createElement(a.a,{to:b,className:p},d)}},460:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},461: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/55af4c9e.6e326dc8.js.LICENSE.txt b/54ad54c7.53bb4f38.js.LICENSE.txt similarity index 100% rename from 55af4c9e.6e326dc8.js.LICENSE.txt rename to 54ad54c7.53bb4f38.js.LICENSE.txt diff --git a/54e7632e.690f9589.js b/54e7632e.b76536ee.js similarity index 97% rename from 54e7632e.690f9589.js rename to 54e7632e.b76536ee.js index 4057594270..6fc00250d4 100644 --- a/54e7632e.690f9589.js +++ b/54e7632e.b76536ee.js @@ -1,2 +1,2 @@ -/*! For license information please see 54e7632e.690f9589.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[102],{443: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 O})),t.d(n,"interval",(function(){return j}));var d,r,a=t(0),c=t.n(a),o=t(585),i=t(471),f=t(454),l=(t(450),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 O=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)},k=Object.assign({},n);t(460);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})))}},447: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}},452: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""}}})},457:function(e,u,t){"use strict";var n=t(0),d=t.n(n),r=t(454),a=t(447),c=t.n(a);t(134);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)}},465:function(e,u,t){"use strict";var n=t(8),d=t(510),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}]}))},471:function(e,u,t){"use strict";t(481);var n=t(0),d=t.n(n),r=t(482),a=t(470),c=t(1),o=(t(472),t(473),t(483),t(454)),i=t(484),f=t(466),l=t.n(f),s=t(485),p=t.n(s),m=t(460),h=t(447),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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),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(486),U=t(487),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)))}},475: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]",O="[object Int8Array]",j="[object Int16Array]",k="[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+")",Oe="(?:"+Se+"|"+_e+")",je="(?:"+ve+"|"+xe+")"+"?",ke="[\\ufe0e\\ufe0f]?"+je+("(?:\\u200d(?:"+[we,Ee,Ie].join("|")+")[\\ufe0e\\ufe0f]?"+je+")*"),Ne="(?:"+[ye,Ee,Ie].join("|")+")"+ke,Ce="(?:"+[we+ve+"?",ve,Ee,Ie,me].join("|")+")",Pe=RegExp("['\u2019]","g"),Te=RegExp(ve,"g"),Me=RegExp(xe+"(?="+xe+")|"+Ce+ke,"g"),Re=RegExp([Se+"?"+ge+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?="+[he,Se,"$"].join("|")+")",Oe+"+(?:['\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[O]=Ue[j]=Ue[k]=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[O]=ze[j]=ze[k]=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:"",Oe=xe.toString,je=Ee.call(he),ke=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 Ot(e){if($a(e)&&!Pa(e)&&!(e instanceof Ct)){if(e instanceof Nt)return e;if(Ie.call(e,"__wrapped__"))return Or(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 kt(){}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 O:case j:case k: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 Od(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=Ot(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:On)(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),Oc=Bd(_c);function jc(e){return null==e?[]:Cu(e,gc(e))}var kc=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=Od(),Gc=Od(!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 Ot.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)}},Ot.ary=ha,Ot.assign=cc,Ot.assignIn=oc,Ot.assignInWith=ic,Ot.assignWith=fc,Ot.at=lc,Ot.before=va,Ot.bind=ba,Ot.bindAll=zc,Ot.bindKey=ya,Ot.castArray=function(){if(!arguments.length)return[];var e=arguments[0];return Pa(e)?e:[e]},Ot.chain=ea,Ot.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):[]},Ot.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)}))},Ot.tail=function(e){var u=null==e?0:e.length;return u?qn(e,1,u):[]},Ot.take=function(e,u,t){return e&&e.length?qn(e,0,(u=t||void 0===u?1:tc(u))<0?0:u):[]},Ot.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):[]},Ot.takeRightWhile=function(e,u){return e&&e.length?ud(e,Zd(u,3),!1,!0):[]},Ot.takeWhile=function(e,u){return e&&e.length?ud(e,Zd(u,3)):[]},Ot.tap=function(e,u){return u(e),e},Ot.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})},Ot.thru=ua,Ot.toArray=ec,Ot.toPairs=Ac,Ot.toPairsIn=Oc,Ot.toPath=function(e){return Pa(e)?pu(e,Sr):Za(e)?[e]:bd(Ir(ac(e)))},Ot.toPlainObject=rc,Ot.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},Ot.unary=function(e){return ha(e,1)},Ot.union=$r,Ot.unionBy=Gr,Ot.unionWith=qr,Ot.uniq=function(e){return e&&e.length?Yn(e):[]},Ot.uniqBy=function(e,u){return e&&e.length?Yn(e,Zd(u,2)):[]},Ot.uniqWith=function(e,u){return u="function"==typeof u?u:void 0,e&&e.length?Yn(e,void 0,u):[]},Ot.unset=function(e,u){return null==e||Xn(e,u)},Ot.unzip=Hr,Ot.unzipWith=Kr,Ot.update=function(e,u,t){return null==e?e:ed(e,u,ad(t))},Ot.updateWith=function(e,u,t,n){return n="function"==typeof n?n:void 0,null==e?e:ed(e,u,ad(t),n)},Ot.values=jc,Ot.valuesIn=function(e){return null==e?[]:Cu(e,_c(e))},Ot.without=Vr,Ot.words=Dc,Ot.wrap=function(e,u){return Sa(ad(u),e)},Ot.xor=Jr,Ot.xorBy=Zr,Ot.xorWith=Qr,Ot.zip=Yr,Ot.zipObject=function(e,u){return dd(e||[],u||[],Wt)},Ot.zipObjectDeep=function(e,u){return dd(e||[],u||[],zn)},Ot.zipWith=Xr,Ot.entries=Ac,Ot.entriesIn=Oc,Ot.extend=oc,Ot.extendWith=ic,Jc(Ot,Ot),Ot.add=ao,Ot.attempt=Uc,Ot.camelCase=kc,Ot.capitalize=Nc,Ot.ceil=co,Ot.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)},Ot.clone=function(e){return Jt(e,4)},Ot.cloneDeep=function(e){return Jt(e,5)},Ot.cloneDeepWith=function(e,u){return Jt(e,5,u="function"==typeof u?u:void 0)},Ot.cloneWith=function(e,u){return Jt(e,4,u="function"==typeof u?u:void 0)},Ot.conformsTo=function(e,u){return null==u||Zt(e,u,gc(u))},Ot.deburr=Cc,Ot.defaultTo=function(e,u){return null==e||e!=e?u:e},Ot.divide=oo,Ot.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},Ot.eq=ja,Ot.escape=function(e){return(e=ac(e))&&D.test(e)?e.replace(F,Fu):e},Ot.escapeRegExp=function(e){return(e=ac(e))&&K.test(e)?e.replace(H,"\\$&"):e},Ot.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))},Ot.find=da,Ot.findIndex=Cr,Ot.findKey=function(e,u){return gu(e,Zd(u,3),cn)},Ot.findLast=ra,Ot.findLastIndex=Pr,Ot.findLastKey=function(e,u){return gu(e,Zd(u,3),on)},Ot.floor=io,Ot.forEach=aa,Ot.forEachRight=ca,Ot.forIn=function(e,u){return null==e?e:rn(e,Zd(u,3),_c)},Ot.forInRight=function(e,u){return null==e?e:an(e,Zd(u,3),_c)},Ot.forOwn=function(e,u){return e&&cn(e,Zd(u,3))},Ot.forOwnRight=function(e,u){return e&&on(e,Zd(u,3))},Ot.get=mc,Ot.gt=ka,Ot.gte=Na,Ot.has=function(e,u){return null!=e&&nr(e,u,hn)},Ot.hasIn=hc,Ot.head=Mr,Ot.identity=qc,Ot.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},Ot.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)},Ot.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},Ot.isSet=Va,Ot.isString=Ja,Ot.isSymbol=Za,Ot.isTypedArray=Qa,Ot.isUndefined=function(e){return void 0===e},Ot.isWeakMap=function(e){return $a(e)&&tr(e)==w},Ot.isWeakSet=function(e){return $a(e)&&"[object WeakSet]"==pn(e)},Ot.join=function(e,u){return null==e?"":nt.call(e,u)},Ot.kebabCase=Pc,Ot.last=Br,Ot.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)},Ot.lowerCase=Tc,Ot.lowerFirst=Mc,Ot.lt=Ya,Ot.lte=Xa,Ot.max=function(e){return e&&e.length?tn(e,qc,mn):void 0},Ot.maxBy=function(e,u){return e&&e.length?tn(e,Zd(u,2),mn):void 0},Ot.mean=function(e){return Iu(e,qc)},Ot.meanBy=function(e,u){return Iu(e,Zd(u,2))},Ot.min=function(e){return e&&e.length?tn(e,qc,An):void 0},Ot.minBy=function(e,u){return e&&e.length?tn(e,Zd(u,2),An):void 0},Ot.stubArray=no,Ot.stubFalse=ro,Ot.stubObject=function(){return{}},Ot.stubString=function(){return""},Ot.stubTrue=function(){return!0},Ot.multiply=lo,Ot.nth=function(e,u){return e&&e.length?Cn(e,tc(u)):void 0},Ot.noConflict=function(){return Ke._===this&&(Ke._=ke),this},Ot.noop=Zc,Ot.now=ma,Ot.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)},Ot.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)},Ot.reduce=function(e,u,t){var n=Pa(e)?hu:Ou,d=arguments.length<3;return n(e,Zd(u,4),t,d,Xt)},Ot.reduceRight=function(e,u,t){var n=Pa(e)?vu:Ou,d=arguments.length<3;return n(e,Zd(u,4),t,d,en)},Ot.repeat=function(e,u,t){return u=(t?cr(e,u,t):void 0===u)?1:tc(u),Fn(ac(e),u)},Ot.replace=function(){var e=arguments,u=ac(e[0]);return e.length<3?u:u.replace(e[1],e[2])},Ot.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=ku(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},Ot.unescape=function(e){return(e=ac(e))&&B.test(e)?e.replace(L,Ku):e},Ot.uniqueId=function(e){var u=++Se;return ac(e)+u},Ot.upperCase=Fc,Ot.upperFirst=Bc,Ot.each=aa,Ot.eachRight=ca,Ot.first=Mr,Jc(Ot,(fo={},cn(Ot,(function(e,u){Ie.call(Ot.prototype,u)||(fo[u]=e)})),fo),{chain:!1}),Ot.VERSION="4.17.15",cu(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(e){Ot[e].placeholder=Ot})),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=Ot[n?"take"+("last"==u?"Right":""):u],r=n||/^find/.test(u);d&&(Ot.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(Ot,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);Ot.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=Ot[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__++]}},Ot.prototype.plant=function(e){for(var u,t=this;t instanceof kt;){var n=Or(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},Ot.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)},Ot.prototype.toJSON=Ot.prototype.valueOf=Ot.prototype.value=function(){return td(this.__wrapped__,this.__actions__)},Ot.prototype.first=Ot.prototype.head,Ye&&(Ot.prototype[Ye]=function(){return this}),Ot}();Ke._=Vu,void 0===(d=function(){return Vu}.call(u,t,u,n))||(n.exports=d)}).call(this)}).call(this,t(76),t(480)(e))},478:function(e,u,t){"use strict";var n=t(0),d=Object(n.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});u.a=d},480: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}},493: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(O){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(531)(),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(494),b=t(534),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}},494:function(e,u,t){"use strict";var n=t(533);e.exports=Function.prototype.bind||n},495: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}},502:function(e,u,t){"use strict";var n=t(495),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},510:function(e,u){e.exports=Object.is||function(e,u){return e===u?0!==e||1/e==1/u:e!=e&&u!=u}},513: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(569),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}})},514:function(e,u,t){"use strict";var n=t(570),d=t(516);e.exports=t(571)("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)},515: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}}},516: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}},517:function(e,u,t){"use strict";const n=t(518);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()}},518:function(e,u,t){"use strict";Object.defineProperty(u,"__esModule",{value:!0});var n=l(t(519)),d=l(t(520)),r=l(t(521)),a=l(t(522)),c=l(t(523)),o=l(t(524)),i=l(t(525)),f=l(t(526));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},519: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 O(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 k(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},520: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},521: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},522: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},525: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},526: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},527: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))}},528:function(e,u,t){"use strict";var n=t(529),d=t(539),r=t(495);e.exports={formats:r,parse:d,stringify:n}},529:function(e,u,t){"use strict";var n=t(530),d=t(502),r=t(495),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,O=0,j=!1;void 0!==(A=A.get(h))&&!j;){var k=A.get(u);if(O+=1,void 0!==k){if(k===O)throw new RangeError("Cyclic object value");j=!0}void 0===A.get(h)&&(O=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+_:""}},530:function(e,u,t){"use strict";var n=t(493),d=t(535),r=t(537),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}},531:function(e,u,t){"use strict";var n="undefined"!=typeof Symbol&&Symbol,d=t(532);e.exports=function(){return"function"==typeof n&&("function"==typeof Symbol&&("symbol"==typeof n("foo")&&("symbol"==typeof Symbol("bar")&&d())))}},532: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}},533: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}},536:function(e,u,t){"use strict";var n=t(494),d=t(493),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},537: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,O="function"==typeof BigInt?BigInt.prototype.valueOf:null,j=Object.getOwnPropertySymbols,k="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(538),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||!k)return!1;try{return k.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"):k.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||!O)return!1;try{return O.call(e),!0}catch(u){}return!1}(u))return V(L(O.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)}}},571:function(e,u,t){"use strict";var n=t(5),d=t(12),r=t(16),a=t(82),c=t(515),o=t(81),i=t(80),f=t(13),l=t(14),s=t(83),p=t(41),m=t(572);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)})),O=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)}));O||((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}},572:function(e,u,t){var n=t(13),d=t(573).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}},573: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(574).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}},574: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])}},575: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(576)(c)),"Array",{sort:function(e){return void 0===e?c.call(r(this)):c.call(r(this),d(e))}})},576: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)}))}},585:function(e,u,t){"use strict";t(513),t(79),t(514),t(575),t(29),t(22),t(21),t(85),t(465);var n=t(1),d=(t(472),t(473),t(77),t(452),t(0)),r=t.n(d),a=t(505),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(527),f=t(457),l=t(454),s=(t(466),t(475)),p=t.n(s),m=t(447),h=t.n(m),v=t(528),b=t.n(v),y=t(460);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],O=S[1],j=Object(d.useState)(new Set(s["operating-systems"])),k=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)}))),k.size>0&&(m=m.filter((function(e){return Array.from(k).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:O}))),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:O}))),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:O}))),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:k,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.b76536ee.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[103],{445: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 O})),t.d(n,"interval",(function(){return j}));var d,r,a=t(0),c=t.n(a),o=t(587),i=t(473),f=t(456),l=(t(452),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 O=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)},k=Object.assign({},n);t(462);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})))}},449: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}},454: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""}}})},459:function(e,u,t){"use strict";var n=t(0),d=t.n(n),r=t(456),a=t(449),c=t.n(a);t(134);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)}},467:function(e,u,t){"use strict";var n=t(8),d=t(512),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}]}))},473:function(e,u,t){"use strict";t(483);var n=t(0),d=t.n(n),r=t(484),a=t(472),c=t(1),o=(t(474),t(475),t(485),t(456)),i=t(486),f=t(468),l=t.n(f),s=t(487),p=t.n(s),m=t(462),h=t(449),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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),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(488),U=t(489),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)))}},477: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]",O="[object Int8Array]",j="[object Int16Array]",k="[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+")",Oe="(?:"+Se+"|"+_e+")",je="(?:"+ve+"|"+xe+")"+"?",ke="[\\ufe0e\\ufe0f]?"+je+("(?:\\u200d(?:"+[we,Ee,Ie].join("|")+")[\\ufe0e\\ufe0f]?"+je+")*"),Ne="(?:"+[ye,Ee,Ie].join("|")+")"+ke,Ce="(?:"+[we+ve+"?",ve,Ee,Ie,me].join("|")+")",Pe=RegExp("['\u2019]","g"),Te=RegExp(ve,"g"),Me=RegExp(xe+"(?="+xe+")|"+Ce+ke,"g"),Re=RegExp([Se+"?"+ge+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?="+[he,Se,"$"].join("|")+")",Oe+"+(?:['\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[O]=Ue[j]=Ue[k]=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[O]=ze[j]=ze[k]=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:"",Oe=xe.toString,je=Ee.call(he),ke=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 Ot(e){if($a(e)&&!Pa(e)&&!(e instanceof Ct)){if(e instanceof Nt)return e;if(Ie.call(e,"__wrapped__"))return Or(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 kt(){}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 O:case j:case k: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 Od(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=Ot(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:On)(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),Oc=Bd(_c);function jc(e){return null==e?[]:Cu(e,gc(e))}var kc=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=Od(),Gc=Od(!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 Ot.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)}},Ot.ary=ha,Ot.assign=cc,Ot.assignIn=oc,Ot.assignInWith=ic,Ot.assignWith=fc,Ot.at=lc,Ot.before=va,Ot.bind=ba,Ot.bindAll=zc,Ot.bindKey=ya,Ot.castArray=function(){if(!arguments.length)return[];var e=arguments[0];return Pa(e)?e:[e]},Ot.chain=ea,Ot.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):[]},Ot.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)}))},Ot.tail=function(e){var u=null==e?0:e.length;return u?qn(e,1,u):[]},Ot.take=function(e,u,t){return e&&e.length?qn(e,0,(u=t||void 0===u?1:tc(u))<0?0:u):[]},Ot.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):[]},Ot.takeRightWhile=function(e,u){return e&&e.length?ud(e,Zd(u,3),!1,!0):[]},Ot.takeWhile=function(e,u){return e&&e.length?ud(e,Zd(u,3)):[]},Ot.tap=function(e,u){return u(e),e},Ot.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})},Ot.thru=ua,Ot.toArray=ec,Ot.toPairs=Ac,Ot.toPairsIn=Oc,Ot.toPath=function(e){return Pa(e)?pu(e,Sr):Za(e)?[e]:bd(Ir(ac(e)))},Ot.toPlainObject=rc,Ot.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},Ot.unary=function(e){return ha(e,1)},Ot.union=$r,Ot.unionBy=Gr,Ot.unionWith=qr,Ot.uniq=function(e){return e&&e.length?Yn(e):[]},Ot.uniqBy=function(e,u){return e&&e.length?Yn(e,Zd(u,2)):[]},Ot.uniqWith=function(e,u){return u="function"==typeof u?u:void 0,e&&e.length?Yn(e,void 0,u):[]},Ot.unset=function(e,u){return null==e||Xn(e,u)},Ot.unzip=Hr,Ot.unzipWith=Kr,Ot.update=function(e,u,t){return null==e?e:ed(e,u,ad(t))},Ot.updateWith=function(e,u,t,n){return n="function"==typeof n?n:void 0,null==e?e:ed(e,u,ad(t),n)},Ot.values=jc,Ot.valuesIn=function(e){return null==e?[]:Cu(e,_c(e))},Ot.without=Vr,Ot.words=Dc,Ot.wrap=function(e,u){return Sa(ad(u),e)},Ot.xor=Jr,Ot.xorBy=Zr,Ot.xorWith=Qr,Ot.zip=Yr,Ot.zipObject=function(e,u){return dd(e||[],u||[],Wt)},Ot.zipObjectDeep=function(e,u){return dd(e||[],u||[],zn)},Ot.zipWith=Xr,Ot.entries=Ac,Ot.entriesIn=Oc,Ot.extend=oc,Ot.extendWith=ic,Jc(Ot,Ot),Ot.add=ao,Ot.attempt=Uc,Ot.camelCase=kc,Ot.capitalize=Nc,Ot.ceil=co,Ot.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)},Ot.clone=function(e){return Jt(e,4)},Ot.cloneDeep=function(e){return Jt(e,5)},Ot.cloneDeepWith=function(e,u){return Jt(e,5,u="function"==typeof u?u:void 0)},Ot.cloneWith=function(e,u){return Jt(e,4,u="function"==typeof u?u:void 0)},Ot.conformsTo=function(e,u){return null==u||Zt(e,u,gc(u))},Ot.deburr=Cc,Ot.defaultTo=function(e,u){return null==e||e!=e?u:e},Ot.divide=oo,Ot.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},Ot.eq=ja,Ot.escape=function(e){return(e=ac(e))&&D.test(e)?e.replace(F,Fu):e},Ot.escapeRegExp=function(e){return(e=ac(e))&&K.test(e)?e.replace(H,"\\$&"):e},Ot.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))},Ot.find=da,Ot.findIndex=Cr,Ot.findKey=function(e,u){return gu(e,Zd(u,3),cn)},Ot.findLast=ra,Ot.findLastIndex=Pr,Ot.findLastKey=function(e,u){return gu(e,Zd(u,3),on)},Ot.floor=io,Ot.forEach=aa,Ot.forEachRight=ca,Ot.forIn=function(e,u){return null==e?e:rn(e,Zd(u,3),_c)},Ot.forInRight=function(e,u){return null==e?e:an(e,Zd(u,3),_c)},Ot.forOwn=function(e,u){return e&&cn(e,Zd(u,3))},Ot.forOwnRight=function(e,u){return e&&on(e,Zd(u,3))},Ot.get=mc,Ot.gt=ka,Ot.gte=Na,Ot.has=function(e,u){return null!=e&&nr(e,u,hn)},Ot.hasIn=hc,Ot.head=Mr,Ot.identity=qc,Ot.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},Ot.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)},Ot.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},Ot.isSet=Va,Ot.isString=Ja,Ot.isSymbol=Za,Ot.isTypedArray=Qa,Ot.isUndefined=function(e){return void 0===e},Ot.isWeakMap=function(e){return $a(e)&&tr(e)==w},Ot.isWeakSet=function(e){return $a(e)&&"[object WeakSet]"==pn(e)},Ot.join=function(e,u){return null==e?"":nt.call(e,u)},Ot.kebabCase=Pc,Ot.last=Br,Ot.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)},Ot.lowerCase=Tc,Ot.lowerFirst=Mc,Ot.lt=Ya,Ot.lte=Xa,Ot.max=function(e){return e&&e.length?tn(e,qc,mn):void 0},Ot.maxBy=function(e,u){return e&&e.length?tn(e,Zd(u,2),mn):void 0},Ot.mean=function(e){return Iu(e,qc)},Ot.meanBy=function(e,u){return Iu(e,Zd(u,2))},Ot.min=function(e){return e&&e.length?tn(e,qc,An):void 0},Ot.minBy=function(e,u){return e&&e.length?tn(e,Zd(u,2),An):void 0},Ot.stubArray=no,Ot.stubFalse=ro,Ot.stubObject=function(){return{}},Ot.stubString=function(){return""},Ot.stubTrue=function(){return!0},Ot.multiply=lo,Ot.nth=function(e,u){return e&&e.length?Cn(e,tc(u)):void 0},Ot.noConflict=function(){return Ke._===this&&(Ke._=ke),this},Ot.noop=Zc,Ot.now=ma,Ot.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)},Ot.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)},Ot.reduce=function(e,u,t){var n=Pa(e)?hu:Ou,d=arguments.length<3;return n(e,Zd(u,4),t,d,Xt)},Ot.reduceRight=function(e,u,t){var n=Pa(e)?vu:Ou,d=arguments.length<3;return n(e,Zd(u,4),t,d,en)},Ot.repeat=function(e,u,t){return u=(t?cr(e,u,t):void 0===u)?1:tc(u),Fn(ac(e),u)},Ot.replace=function(){var e=arguments,u=ac(e[0]);return e.length<3?u:u.replace(e[1],e[2])},Ot.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=ku(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},Ot.unescape=function(e){return(e=ac(e))&&B.test(e)?e.replace(L,Ku):e},Ot.uniqueId=function(e){var u=++Se;return ac(e)+u},Ot.upperCase=Fc,Ot.upperFirst=Bc,Ot.each=aa,Ot.eachRight=ca,Ot.first=Mr,Jc(Ot,(fo={},cn(Ot,(function(e,u){Ie.call(Ot.prototype,u)||(fo[u]=e)})),fo),{chain:!1}),Ot.VERSION="4.17.15",cu(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(e){Ot[e].placeholder=Ot})),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=Ot[n?"take"+("last"==u?"Right":""):u],r=n||/^find/.test(u);d&&(Ot.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(Ot,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);Ot.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=Ot[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__++]}},Ot.prototype.plant=function(e){for(var u,t=this;t instanceof kt;){var n=Or(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},Ot.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)},Ot.prototype.toJSON=Ot.prototype.valueOf=Ot.prototype.value=function(){return td(this.__wrapped__,this.__actions__)},Ot.prototype.first=Ot.prototype.head,Ye&&(Ot.prototype[Ye]=function(){return this}),Ot}();Ke._=Vu,void 0===(d=function(){return Vu}.call(u,t,u,n))||(n.exports=d)}).call(this)}).call(this,t(76),t(482)(e))},480:function(e,u,t){"use strict";var n=t(0),d=Object(n.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});u.a=d},482: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}},495: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(O){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(533)(),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(496),b=t(536),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}},496:function(e,u,t){"use strict";var n=t(535);e.exports=Function.prototype.bind||n},497: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}},504:function(e,u,t){"use strict";var n=t(497),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},512:function(e,u){e.exports=Object.is||function(e,u){return e===u?0!==e||1/e==1/u:e!=e&&u!=u}},515: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(571),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}})},516:function(e,u,t){"use strict";var n=t(572),d=t(518);e.exports=t(573)("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)},517: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}}},518: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}},519:function(e,u,t){"use strict";const n=t(520);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()}},520:function(e,u,t){"use strict";Object.defineProperty(u,"__esModule",{value:!0});var n=l(t(521)),d=l(t(522)),r=l(t(523)),a=l(t(524)),c=l(t(525)),o=l(t(526)),i=l(t(527)),f=l(t(528));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},521: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 O(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 k(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},522: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},523: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},524: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},527: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},528: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},529: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))}},530:function(e,u,t){"use strict";var n=t(531),d=t(541),r=t(497);e.exports={formats:r,parse:d,stringify:n}},531:function(e,u,t){"use strict";var n=t(532),d=t(504),r=t(497),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,O=0,j=!1;void 0!==(A=A.get(h))&&!j;){var k=A.get(u);if(O+=1,void 0!==k){if(k===O)throw new RangeError("Cyclic object value");j=!0}void 0===A.get(h)&&(O=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+_:""}},532:function(e,u,t){"use strict";var n=t(495),d=t(537),r=t(539),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}},533:function(e,u,t){"use strict";var n="undefined"!=typeof Symbol&&Symbol,d=t(534);e.exports=function(){return"function"==typeof n&&("function"==typeof Symbol&&("symbol"==typeof n("foo")&&("symbol"==typeof Symbol("bar")&&d())))}},534: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}},535: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}},538:function(e,u,t){"use strict";var n=t(496),d=t(495),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},539: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,O="function"==typeof BigInt?BigInt.prototype.valueOf:null,j=Object.getOwnPropertySymbols,k="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(540),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||!k)return!1;try{return k.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"):k.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||!O)return!1;try{return O.call(e),!0}catch(u){}return!1}(u))return V(L(O.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)}}},573:function(e,u,t){"use strict";var n=t(5),d=t(12),r=t(16),a=t(82),c=t(517),o=t(81),i=t(80),f=t(13),l=t(14),s=t(83),p=t(41),m=t(574);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)})),O=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)}));O||((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}},574:function(e,u,t){var n=t(13),d=t(575).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}},575: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(576).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}},576: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])}},577: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(578)(c)),"Array",{sort:function(e){return void 0===e?c.call(r(this)):c.call(r(this),d(e))}})},578: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)}))}},587:function(e,u,t){"use strict";t(515),t(79),t(516),t(577),t(29),t(22),t(21),t(85),t(467);var n=t(1),d=(t(474),t(475),t(77),t(454),t(0)),r=t.n(d),a=t(507),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(529),f=t(459),l=t(456),s=(t(468),t(477)),p=t.n(s),m=t(449),h=t.n(m),v=t(530),b=t.n(v),y=t(462);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],O=S[1],j=Object(d.useState)(new Set(s["operating-systems"])),k=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)}))),k.size>0&&(m=m.filter((function(e){return Array.from(k).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:O}))),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:O}))),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:O}))),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:k,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.690f9589.js.LICENSE.txt b/54e7632e.b76536ee.js.LICENSE.txt similarity index 100% rename from 54e7632e.690f9589.js.LICENSE.txt rename to 54e7632e.b76536ee.js.LICENSE.txt diff --git a/55af4c9e.6e326dc8.js b/55af4c9e.88438eaf.js similarity index 93% rename from 55af4c9e.6e326dc8.js rename to 55af4c9e.88438eaf.js index b283b44ce2..7e884b136d 100644 --- a/55af4c9e.6e326dc8.js +++ b/55af4c9e.88438eaf.js @@ -1,2 +1,2 @@ -/*! For license information please see 55af4c9e.6e326dc8.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 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(449)),a=n(456),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},447: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||(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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var i=n(0),a=n.n(i),r=n(448);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)}},454:function(e,t,n){"use strict";var i=n(1),a=n(0),r=n.n(a),o=n(39),l=n(458),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}))}},457:function(e,t,n){"use strict";var i=n(0),a=n.n(i),r=n(454),o=n(447),l=n.n(o);n(134);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)}},458: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 55ef6d6a.59ec5c36.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[105],{256: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(451)),o=(n(459),n(450)),l=n(455),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var i=n(0),a=n.n(i),r=n(450);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)}},456:function(e,t,n){"use strict";var i=n(1),a=n(0),r=n.n(a),o=n(39),l=n(460),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}))}},459:function(e,t,n){"use strict";var i=n(0),a=n.n(i),r=n(456),o=n(449),l=n.n(o);n(134);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)}},460: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/56cfbe62.8a449a0b.js.LICENSE.txt b/55ef6d6a.59ec5c36.js.LICENSE.txt similarity index 100% rename from 56cfbe62.8a449a0b.js.LICENSE.txt rename to 55ef6d6a.59ec5c36.js.LICENSE.txt diff --git a/56c0a343.ec3273e1.js b/56c0a343.54bdf029.js similarity index 98% rename from 56c0a343.ec3273e1.js rename to 56c0a343.54bdf029.js index 97c87b2292..d7375df0cc 100644 --- a/56c0a343.ec3273e1.js +++ b/56c0a343.54bdf029.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[105],{256: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(449)),i=n(448),l=(n(461),n(453)),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},448:function(e,t,n){"use strict";n(450);var a=n(0),o=n.n(a),r=n(447),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)}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),o=n.n(a),r=n(448);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)}},461:function(e,t,n){"use strict";var a=n(1),o=(n(465),n(462),n(52),n(29),n(22),n(21),n(0)),r=n.n(o),i=n(469),l=n(447),s=n.n(l),c=n(455),b=n.n(c),u=n(468),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([[106],{257: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(451)),i=n(450),l=(n(463),n(455)),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},450:function(e,t,n){"use strict";n(452);var a=n(0),o=n.n(a),r=n(449),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)}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),o=n.n(a),r=n(450);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)}},463:function(e,t,n){"use strict";var a=n(1),o=(n(467),n(464),n(52),n(29),n(22),n(21),n(0)),r=n.n(o),i=n(471),l=n(449),s=n.n(l),c=n(457),b=n.n(c),u=n(470),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.8a449a0b.js b/56cfbe62.b7ca6f2c.js similarity index 89% rename from 56cfbe62.8a449a0b.js rename to 56cfbe62.b7ca6f2c.js index 601167af04..2f3bd3fba4 100644 --- a/56cfbe62.8a449a0b.js +++ b/56cfbe62.b7ca6f2c.js @@ -1,2 +1,2 @@ -/*! For license information please see 56cfbe62.8a449a0b.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 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(449)),c=n(457),i={last_modified_on:"2023-12-22",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},447: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}))}},457:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(454),c=n(447),i=n.n(c);n(134);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)}},458: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.b7ca6f2c.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 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(451)),c=n(459),i={last_modified_on:"2023-12-22",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},449: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}))}},459:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(456),c=n(449),i=n.n(c);n(134);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)}},460: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/58379094.bccd022a.js.LICENSE.txt b/56cfbe62.b7ca6f2c.js.LICENSE.txt similarity index 100% rename from 58379094.bccd022a.js.LICENSE.txt rename to 56cfbe62.b7ca6f2c.js.LICENSE.txt diff --git a/58379094.bccd022a.js b/58379094.67f2cfe2.js similarity index 91% rename from 58379094.bccd022a.js rename to 58379094.67f2cfe2.js index 2cdcc035a4..eb4ac33926 100644 --- a/58379094.bccd022a.js +++ b/58379094.67f2cfe2.js @@ -1,2 +1,2 @@ -/*! For license information please see 58379094.bccd022a.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[107],{258: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 p})),r.d(t,"default",(function(){return u}));var n=r(1),o=r(9),a=(r(0),r(449)),i=r(448),c={last_modified_on:"2024-03-01",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"}},p=[{value:"First sign-up",id:"first-sign-up",children:[]},{value:"Deploy your first application",id:"deploy-your-first-application",children:[]}],l={rightToc:p};function u(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)(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://console.qovery.com/"},Object(a.b)("img",{src:"/img/Qovery_Sign_Up_Page.png",alt:"Qovery Sign-up page"}))),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"If you log in with the Google or Microsoft providers you will have to setup a git token to access and deploy your applications from your private repositories. "),Object(a.b)("p",null,"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 Git Tokens"),".")),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},447: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 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},u=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)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(r),b=n,y=u["".concat(i,".").concat(b)]||u[b]||f[b]||a;return r?o.a.createElement(y,c({ref:t},p,{components:r})):o.a.createElement(y,c({ref:t},p))}));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 p=2;p1?arguments[1]:void 0,r),s=i>2?arguments[2]:void 0,p=void 0===s?r:o(s,r);p>c;)t[c++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see 58379094.67f2cfe2.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[108],{259: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 p})),r.d(t,"default",(function(){return u}));var n=r(1),o=r(9),a=(r(0),r(451)),i=r(450),c={last_modified_on:"2024-03-01",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"}},p=[{value:"First sign-up",id:"first-sign-up",children:[]},{value:"Deploy your first application",id:"deploy-your-first-application",children:[]}],l={rightToc:p};function u(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)(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://console.qovery.com/"},Object(a.b)("img",{src:"/img/Qovery_Sign_Up_Page.png",alt:"Qovery Sign-up page"}))),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"If you log in with the Google or Microsoft providers you will have to setup a git token to access and deploy your applications from your private repositories. "),Object(a.b)("p",null,"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 Git Tokens"),".")),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},449: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 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},u=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)}},b=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(r),b=n,y=u["".concat(i,".").concat(b)]||u[b]||f[b]||a;return r?o.a.createElement(y,c({ref:t},p,{components:r})):o.a.createElement(y,c({ref:t},p))}));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 p=2;p1?arguments[1]:void 0,r),s=i>2?arguments[2]:void 0,p=void 0===s?r:o(s,r);p>c;)t[c++]=e;return t}}}]); \ No newline at end of file diff --git a/592d28ca.00a6fda5.js.LICENSE.txt b/58379094.67f2cfe2.js.LICENSE.txt similarity index 100% rename from 592d28ca.00a6fda5.js.LICENSE.txt rename to 58379094.67f2cfe2.js.LICENSE.txt diff --git a/59157ba2.6be99b57.js b/59157ba2.0cb546fc.js similarity index 98% rename from 59157ba2.6be99b57.js rename to 59157ba2.0cb546fc.js index df3ce2d92e..11c1290fde 100644 --- a/59157ba2.6be99b57.js +++ b/59157ba2.0cb546fc.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[108],{259: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(449)),i={last_modified_on:"2024-04-15",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:"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/roadmap"}),"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, you can connect directly to your application with a shell by clicking on the Qovery cloud shell button (1):"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/qovery_cloud_shell.png",alt:"Qovery Cloud Shell"})),Object(a.b)("p",null,"Then you just have to select the pod (2) and the container (3)."),Object(a.b)("p",null,"You can also 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:"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://discuss.qovery.com/"}),"forum")," or contact us by email at hello (at) qovery.com or via the Intercom chat."))}l.isMDXComponent=!0},449: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,m=d["".concat(a,".").concat(f)]||d[f]||p[f]||i;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 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}},454:function(e,t,n){"use strict";var r=n(1),o=n(0),i=n.n(o),a=n(39),c=n(458),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}))}},457:function(e,t,n){"use strict";var r=n(0),o=n.n(r),i=n(454),a=n(447),c=n.n(a);n(134);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)}},458: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.255fe2c5.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[110],{261: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(451)),a=n(450),c=n(459),l={last_modified_on:"2024-01-03",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 deploying the helm chart with Qovery",id:"by-deploying-the-helm-chart-with-qovery",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-deploying-the-helm-chart-with-qovery"},"By deploying the helm chart with Qovery"),Object(i.b)("ol",null,Object(i.b)("li",{parentName:"ol"},"Follow ",Object(i.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/helm/"}),"this guide")," to deploy your Helm Chart with Qovery.")),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},449: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,m=d["".concat(a,".").concat(f)]||d[f]||p[f]||i;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 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}},456:function(e,t,n){"use strict";var r=n(1),o=n(0),i=n.n(o),a=n(39),c=n(460),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}))}},459:function(e,t,n){"use strict";var r=n(0),o=n.n(r),i=n(456),a=n(449),c=n.n(a);n(134);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)}},460: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/5b5f8b70.75d70926.js.LICENSE.txt b/592d28ca.255fe2c5.js.LICENSE.txt similarity index 100% rename from 5b5f8b70.75d70926.js.LICENSE.txt rename to 592d28ca.255fe2c5.js.LICENSE.txt diff --git a/5b5f8b70.75d70926.js b/5b5f8b70.8f461783.js similarity index 95% rename from 5b5f8b70.75d70926.js rename to 5b5f8b70.8f461783.js index 67a3b2ceeb..9e158fabfe 100644 --- a/5b5f8b70.75d70926.js +++ b/5b5f8b70.8f461783.js @@ -1,2 +1,2 @@ -/*! For license information please see 5b5f8b70.75d70926.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[110],{261: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),i=n(9),r=(n(0),n(449)),o=(n(457),n(448)),c=(n(453),{last_modified_on:"2024-05-02",$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:"7 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:"Deploy a service account with Helm",id:"deploy-a-service-account-with-helm",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 p(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 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 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:"deploy-a-service-account-with-helm"},"Deploy a service account with Helm"),Object(r.b)("p",null,"Qovery provides a simple Helm chart to deploy a service account on your Kubernetes cluster in a specific environment (Kubernetes namespace). "),Object(r.b)("p",null,"Start to create a new service, with an Helm chart:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/create_sa.png",alt:"Create Service Account"})),Object(r.b)("p",null,"Then configure the Helm chart with the following values:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/helm_sa_1.png",alt:"Helm chart"})),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Helm source: ",Object(r.b)("inlineCode",{parentName:"li"},"Helm repository")),Object(r.b)("li",{parentName:"ul"},"Git repository: ",Object(r.b)("inlineCode",{parentName:"li"},"Qovery Service Account Helper")),Object(r.b)("li",{parentName:"ul"},"Chart name: ",Object(r.b)("inlineCode",{parentName:"li"},"qovery-sa-helper")),Object(r.b)("li",{parentName:"ul"},"Version: ",Object(r.b)("inlineCode",{parentName:"li"},"0.1.0"))),Object(r.b)("p",null,"Create a new help repository on phase 3, and fill the chart info:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/set-helm-repo.png",alt:"Helm chart"})),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Repository name: ",Object(r.b)("inlineCode",{parentName:"li"},"Qovery Service Account Helper")),Object(r.b)("li",{parentName:"ul"},"Kind: HTTPS"),Object(r.b)("li",{parentName:"ul"},"Repository url: ",Object(r.b)("inlineCode",{parentName:"li"},"https://qovery.github.io/create_service_account/"))),Object(r.b)("p",null,"Then click on ",Object(r.b)("inlineCode",{parentName:"p"},"Create"),", and the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button."),Object(r.b)("p",null,"On the values override file, we do not need to override anything, so select ",Object(r.b)("inlineCode",{parentName:"p"},"None"),", and then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/helm_sa_2.png",alt:"Helm chart"})),Object(r.b)("p",null,"We then have to add 2 override arguments:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},Object(r.b)("inlineCode",{parentName:"li"},"serviceAccount.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:"ol"},Object(r.b)("inlineCode",{parentName:"li"},"awsRoleArn"),": the ARN of the role you have created")),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/helm_sa_3.png",alt:"Helm chart"})),Object(r.b)("p",null,"Then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button."),Object(r.b)("p",null,"You can finally Create and Deploy it. If you look at the logs, you should see something like:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/helm_sa_logs.png",alt:"Helm chart"})),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 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!"))}p.isMDXComponent=!0},447: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},p=function(e){var t=b(e.components);return i.a.createElement(s.Provider,{value:t},e.children)},u={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"]),p=b(n),m=a,d=p["".concat(o,".").concat(m)]||p[m]||u[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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),i=n.n(a),r=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),i=n(0),r=n.n(i),o=n(39),c=n(458),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,b=n||l,p=Object(c.a)(b),u=Object(i.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!m&&p&&window.docusaurus.prefetch(b),function(){m&&t&&t.disconnect()}}),[b,m,p]),b&&p?r.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})):r.a.createElement("a",Object(a.a)({},e,{href:b}))}},457:function(e,t,n){"use strict";var a=n(0),i=n.n(a),r=n(454),o=n(447),c=n.n(o);n(134);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=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 b?i.a.createElement("a",{href:p,target:b,className:u},m):i.a.createElement(r.a,{to:p,className:u},m)}},458: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.8f461783.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 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),i=n(9),r=(n(0),n(451)),o=(n(459),n(450)),c=(n(455),{last_modified_on:"2024-05-02",$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:"7 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:"Deploy a service account with Helm",id:"deploy-a-service-account-with-helm",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 p(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 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 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:"deploy-a-service-account-with-helm"},"Deploy a service account with Helm"),Object(r.b)("p",null,"Qovery provides a simple Helm chart to deploy a service account on your Kubernetes cluster in a specific environment (Kubernetes namespace). "),Object(r.b)("p",null,"Start to create a new service, with an Helm chart:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/create_sa.png",alt:"Create Service Account"})),Object(r.b)("p",null,"Then configure the Helm chart with the following values:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/helm_sa_1.png",alt:"Helm chart"})),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Helm source: ",Object(r.b)("inlineCode",{parentName:"li"},"Helm repository")),Object(r.b)("li",{parentName:"ul"},"Git repository: ",Object(r.b)("inlineCode",{parentName:"li"},"Qovery Service Account Helper")),Object(r.b)("li",{parentName:"ul"},"Chart name: ",Object(r.b)("inlineCode",{parentName:"li"},"qovery-sa-helper")),Object(r.b)("li",{parentName:"ul"},"Version: ",Object(r.b)("inlineCode",{parentName:"li"},"0.1.0"))),Object(r.b)("p",null,"Create a new help repository on phase 3, and fill the chart info:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/set-helm-repo.png",alt:"Helm chart"})),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Repository name: ",Object(r.b)("inlineCode",{parentName:"li"},"Qovery Service Account Helper")),Object(r.b)("li",{parentName:"ul"},"Kind: HTTPS"),Object(r.b)("li",{parentName:"ul"},"Repository url: ",Object(r.b)("inlineCode",{parentName:"li"},"https://qovery.github.io/create_service_account/"))),Object(r.b)("p",null,"Then click on ",Object(r.b)("inlineCode",{parentName:"p"},"Create"),", and the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button."),Object(r.b)("p",null,"On the values override file, we do not need to override anything, so select ",Object(r.b)("inlineCode",{parentName:"p"},"None"),", and then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/helm_sa_2.png",alt:"Helm chart"})),Object(r.b)("p",null,"We then have to add 2 override arguments:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},Object(r.b)("inlineCode",{parentName:"li"},"serviceAccount.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:"ol"},Object(r.b)("inlineCode",{parentName:"li"},"awsRoleArn"),": the ARN of the role you have created")),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/helm_sa_3.png",alt:"Helm chart"})),Object(r.b)("p",null,"Then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button."),Object(r.b)("p",null,"You can finally Create and Deploy it. If you look at the logs, you should see something like:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/helm_sa_logs.png",alt:"Helm chart"})),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 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!"))}p.isMDXComponent=!0},449: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},p=function(e){var t=b(e.components);return i.a.createElement(s.Provider,{value:t},e.children)},u={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"]),p=b(n),m=a,d=p["".concat(o,".").concat(m)]||p[m]||u[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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),i=n.n(a),r=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),i=n(0),r=n.n(i),o=n(39),c=n(460),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,b=n||l,p=Object(c.a)(b),u=Object(i.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!m&&p&&window.docusaurus.prefetch(b),function(){m&&t&&t.disconnect()}}),[b,m,p]),b&&p?r.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})):r.a.createElement("a",Object(a.a)({},e,{href:b}))}},459:function(e,t,n){"use strict";var a=n(0),i=n.n(a),r=n(456),o=n(449),c=n.n(o);n(134);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=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 b?i.a.createElement("a",{href:p,target:b,className:u},m):i.a.createElement(r.a,{to:p,className:u},m)}},460: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/5b8d4026.61242b5b.js.LICENSE.txt b/5b5f8b70.8f461783.js.LICENSE.txt similarity index 100% rename from 5b8d4026.61242b5b.js.LICENSE.txt rename to 5b5f8b70.8f461783.js.LICENSE.txt diff --git a/5b8d4026.61242b5b.js b/5b8d4026.01172cbd.js similarity index 91% rename from 5b8d4026.61242b5b.js rename to 5b8d4026.01172cbd.js index f028545a11..a4fe912de5 100644 --- a/5b8d4026.61242b5b.js +++ b/5b8d4026.01172cbd.js @@ -1,2 +1,2 @@ -/*! For license information please see 5b8d4026.61242b5b.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[111],{262:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),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(449)),c=(a(457),a(448)),i=(a(453),{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:"GitOps with Qovery",permalink:"/guides/tutorial/gitops-with-qovery"},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)(c.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)(c.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},447: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):i({},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,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(a),d=n,f=p["".concat(c,".").concat(d)]||p[d]||b[d]||o;return a?r.a.createElement(f,i({ref:t},s,{components:a})):r.a.createElement(f,i({ref:t},s))}));function f(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.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 s=2;s1?arguments[1]:void 0,a),l=c>2?arguments[2]:void 0,s=void 0===l?a:r(l,a);s>i;)t[i++]=e;return t}},452: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""}}})},453:function(e,t,a){"use strict";a(452);var n=a(0),r=a.n(n),o=a(448);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)}},454:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),c=a(39),i=a(458),l=a(20),s=a.n(l);t.a=function(e){var t,a=e.to,l=e.href,u=a||l,p=Object(i.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(c.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}))}},457:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(454),c=a(447),i=a.n(c);a(134);t.a=function(e){var t=e.children,a=e.className,n=e.badge,c=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,p=e.to,b=i()("jump-to","jump-to--"+s,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-"+(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)}},458: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.01172cbd.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[112],{263:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),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(451)),c=(a(459),a(450)),i=(a(455),{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:"GitOps with Qovery",permalink:"/guides/tutorial/gitops-with-qovery"},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)(c.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)(c.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},449: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):i({},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,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(a),d=n,f=p["".concat(c,".").concat(d)]||p[d]||b[d]||o;return a?r.a.createElement(f,i({ref:t},s,{components:a})):r.a.createElement(f,i({ref:t},s))}));function f(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.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 s=2;s1?arguments[1]:void 0,a),l=c>2?arguments[2]:void 0,s=void 0===l?a:r(l,a);s>i;)t[i++]=e;return t}},454: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""}}})},455:function(e,t,a){"use strict";a(454);var n=a(0),r=a.n(n),o=a(450);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)}},456:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),c=a(39),i=a(460),l=a(20),s=a.n(l);t.a=function(e){var t,a=e.to,l=e.href,u=a||l,p=Object(i.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(c.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}))}},459:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(456),c=a(449),i=a.n(c);a(134);t.a=function(e){var t=e.children,a=e.className,n=e.badge,c=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,p=e.to,b=i()("jump-to","jump-to--"+s,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-"+(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)}},460: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/5b95bed2.a771b7a4.js.LICENSE.txt b/5b8d4026.01172cbd.js.LICENSE.txt similarity index 100% rename from 5b95bed2.a771b7a4.js.LICENSE.txt rename to 5b8d4026.01172cbd.js.LICENSE.txt diff --git a/5b95bed2.a771b7a4.js b/5b95bed2.9d411b04.js similarity index 96% rename from 5b95bed2.a771b7a4.js rename to 5b95bed2.9d411b04.js index 1b33710c93..dc8b4328a4 100644 --- a/5b95bed2.a771b7a4.js +++ b/5b95bed2.9d411b04.js @@ -1,2 +1,2 @@ -/*! For license information please see 5b95bed2.a771b7a4.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[112],{263: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(449)),i=t(448),s=(t(453),t(457),{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},447: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}},452: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""}}})},453:function(e,n,t){"use strict";t(452);var a=t(0),r=t.n(a),o=t(448);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)}},454:function(e,n,t){"use strict";var a=t(1),r=t(0),o=t.n(r),i=t(39),s=t(458),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}))}},457:function(e,n,t){"use strict";var a=t(0),r=t.n(a),o=t(454),i=t(447),s=t.n(i);t(134);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)}},458: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.9d411b04.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[113],{264: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(451)),i=t(450),s=(t(455),t(459),{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},449: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}},454: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""}}})},455:function(e,n,t){"use strict";t(454);var a=t(0),r=t.n(a),o=t(450);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)}},456:function(e,n,t){"use strict";var a=t(1),r=t(0),o=t.n(r),i=t(39),s=t(460),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}))}},459:function(e,n,t){"use strict";var a=t(0),r=t.n(a),o=t(456),i=t(449),s=t.n(i);t(134);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)}},460: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/5e5fefd2.8c7bea29.js.LICENSE.txt b/5b95bed2.9d411b04.js.LICENSE.txt similarity index 100% rename from 5e5fefd2.8c7bea29.js.LICENSE.txt rename to 5b95bed2.9d411b04.js.LICENSE.txt diff --git a/5e5fefd2.8c7bea29.js b/5e5fefd2.8c7bea29.js deleted file mode 100644 index a512b8b766..0000000000 --- a/5e5fefd2.8c7bea29.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see 5e5fefd2.8c7bea29.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[113],{264: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(449)),i=(n(456),n(453),n(448),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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/5e5fefd2.a3f876c4.js b/5e5fefd2.a3f876c4.js new file mode 100644 index 0000000000..156cde33e3 --- /dev/null +++ b/5e5fefd2.a3f876c4.js @@ -0,0 +1,2 @@ +/*! For license information please see 5e5fefd2.a3f876c4.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[114],{265: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(451)),i=(n(458),n(455),n(450),{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:"Deploy a DaemonSet in a Karpenter context",permalink:"/guides/advanced/deploy-daemonset-with-karpenter"},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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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/6308ca27.196ecb87.js.LICENSE.txt b/5e5fefd2.a3f876c4.js.LICENSE.txt similarity index 100% rename from 6308ca27.196ecb87.js.LICENSE.txt rename to 5e5fefd2.a3f876c4.js.LICENSE.txt diff --git a/5e60e078.9b49551c.js b/5e60e078.b6dff916.js similarity index 94% rename from 5e60e078.9b49551c.js rename to 5e60e078.b6dff916.js index 41348dc28f..05ae015452 100644 --- a/5e60e078.9b49551c.js +++ b/5e60e078.b6dff916.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[114],{265: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(449)),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},449: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;u1&&(i?o.a.createElement(h,Object(n.a)({changeSelectedValue:x,handleKeydown:q,placeholder:s,selectedValue:N,size:y,tabRefs:I},e)):o.a.createElement(m,Object(n.a)({changeSelectedValue:x,handleKeydown:q,selectedValue:N,tabRefs:I},e)))),l.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},464: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([[116],{267:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return u})),a.d(t,"metadata",(function(){return b})),a.d(t,"rightToc",(function(){return p})),a.d(t,"default",(function(){return m}));var n=a(1),l=a(9),o=(a(0),a(451)),r=a(450),c=a(463),s=a(466),i=a(458),u={last_modified_on:"2024-07-16",title:"Local",description:"Install Qovery on your local machine"},b={id:"getting-started/install-qovery/local",title:"Local",description:"Install Qovery on your local machine",source:"@site/docs/getting-started/install-qovery/local.md",permalink:"/docs/getting-started/install-qovery/local",sidebar:"docs",previous:{title:"Install Qovery",permalink:"/docs/getting-started/install-qovery"},next:{title:"AWS",permalink:"/docs/getting-started/install-qovery/aws"}},p=[{value:"Purpose and Limitations",id:"purpose-and-limitations",children:[]},{value:"Requirements",id:"requirements",children:[]},{value:"Installation",id:"installation",children:[]},{value:"Cleanup your local environment",id:"cleanup-your-local-environment",children:[]}],d={rightToc:p};function m(e){var t=e.components,a=Object(l.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},d,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Here is how to install Qovery on your local machine. This is the fastest way to get started with Qovery and start deploying your applications to experience the Qovery experience."),Object(o.b)("h2",{id:"purpose-and-limitations"},"Purpose and Limitations"),Object(o.b)("p",null,"It's important to note that this local setup of Qovery using the ",Object(o.b)("inlineCode",{parentName:"p"},"qovery demo up")," command is designed for demonstration and testing purposes only. It is not intended for production use. Please refer to other guides for production-grade installations."),Object(o.b)("h2",{id:"requirements"},"Requirements"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Supported Operating Systems"),": Linux, MacOS, and Windows (only on WSL)."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Resources"),": 4 CPU and 8GB of RAM for your Docker runtime."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("strong",{parentName:"li"},"Binaries"),": ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://www.docker.com/"}),"docker")," (up and running), git."),Object(o.b)("li",{parentName:"ul"},"A stable Internet connection."),Object(o.b)("li",{parentName:"ul"},"A Qovery account. If you don't have one, please sign up at ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://start.qovery.com"}),"https://start.qovery.com"))),Object(o.b)("h2",{id:"installation"},"Installation"),Object(o.b)("p",null,"To install Qovery on your local machine, follow these steps:"),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery CLI by running the following command:"),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)(s.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)(s.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)(s.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)(s.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)(s.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)(s.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)(s.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)(s.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)(s.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)(s.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)(s.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)(s.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)("p",null,"Authenticate with Qovery by running the following command:"),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)(r.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are using a headless (without GUI) environment, you can use the following command to sign up and sign in:"),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 Qovery sign-up page will open. Follow the instructions to sign up and sign in.")),Object(o.b)("li",null,Object(o.b)("p",null,"Set Qovery context:"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"\nqovery context set\n\n"))),Object(o.b)("li",null,Object(o.b)("p",null,"Start the Qovery demo by running the following command:"),Object(o.b)(r.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Ensure you have ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.docker.com/"}),"Docker")," running and that you have installed jq, curl, sed, grep, and git.")),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"\nqovery demo up\n\n")),Object(o.b)("p",null,"A k3s Kubernetes cluster will be installed on your local machine and Qovery will be installed on top of it."),Object(o.b)("p",null,"Note that if you are on MacOS or Windows, you might be prompted for your admin password - which is necessary to properly route the traffic from your host to your k3s apps."),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-shell"}),'...\n""""""""""""""""""""""""""""""""""""""""""""\nConfigure network\n""""""""""""""""""""""""""""""""""""""""""""\n+ sudo ifconfig lo0 alias 172.42.0.3/32 up\nPassword:\n...\n')),Object(o.b)("p",null,"At the end of the installation, you will see the following message:"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-shell"}),'...\n\n""""""""""""""""""""""""""""""""""""""""""""\nQovery demo cluster is now installed !!!!\nThe kubeconfig is correctly set, so you can connect to it directly with kubectl or k9s from your local machine\nTo delete/stop/start your cluster, use k3d cluster xxxx\n\nGo to https://console.qovery.com to create your first environment on this cluster \'hello-local-cluster\'\n""""""""""""""""""""""""""""""""""""""""""""\n'))),Object(o.b)("li",null,Object(o.b)("p",null,"Access the Qovery dashboard by visiting ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"https://console.qovery.com"}),"console.qovery.com"),".")))),Object(o.b)("p",null,"Well done, you have successfully installed Qovery on your local machine. You can now start deploying your applications and experience the Qovery experience."),Object(o.b)("h2",{id:"cleanup-your-local-environment"},"Cleanup your local environment"),Object(o.b)("p",null,"To clean up your local environment, run the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(n.a)({parentName:"pre"},{className:"language-bash"}),"\nqovery demo destroy\n\n")),Object(o.b)("p",null,"That's it! You have successfully removed the Qovery demo cluster from your local machine."))}m.isMDXComponent=!0},450:function(e,t,a){"use strict";a(452);var n=a(0),l=a.n(n),o=a(449),r=a.n(o);a(132);t.a=function(e){var t=e.children,a=e.classNames,n=e.fill,o=e.icon,c=e.type,s=null;switch(c){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return l.a.createElement("div",{className:r()(a,"alert","alert--"+c,{"alert--fill":n,"alert--icon":!1!==o}),role:"alert"},!1!==o&&l.a.createElement("i",{className:r()("feather","icon-"+(o||s))}),t)}},458:function(e,t,a){"use strict";var n=a(0),l=a.n(n),o=(a(449),a(457)),r=a.n(o);a(133);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"},i="https://github.com/qovery/documentation/issues/new?"+r.a.stringify(s),u=Object(n.useState)(null),b=u[0],p=u[1];return l.a.createElement("div",{className:"steps steps--h"+a},t,!o&&!b&&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:i,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==b&&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"),"."))}},463:function(e,t,a){"use strict";var n=a(1),l=(a(467),a(464),a(52),a(29),a(22),a(21),a(0)),o=a.n(l),r=a(471),c=a(449),s=a.n(c),i=a(457),u=a.n(i),b=a(470),p=37,d=39;function m(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,l=e.className,r=e.handleKeydown,c=e.style,i=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:s()("tabs",l,{"tabs--block":t}),style:c},i.map((function(e){var t=e.value,a=e.label;return o.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":u===t,className:s()("tab-item",{"tab-item--active":u===t}),key:t,ref:function(e){return b.push(e)},onKeyDown:function(e){return r(b,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,c=e.values,s=c;if(s[0].group){var i=_.groupBy(s,"group");s=Object.keys(i).map((function(e){return{label:e,options:i[e]}}))}return o.a.createElement(r.a,{className:"react-select-container react-select--"+l,classNamePrefix:"react-select",options:s,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,r=e.groupId,c=e.label,s=e.placeholder,i=e.select,y=e.size,v=(e.style,e.values),O=e.urlKey,j=Object(b.a)(),g=j.tabGroupChoices,f=j.setTabGroupChoices,w=Object(l.useState)(a),N=w[0],T=w[1];if(null!=r){var k=g[r];null!=k&&k!==N&&T(k)}var x=function(e){T(e),null!=r&&f(r,e)},I=[],q=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=u.a.parse(window.location.search);e[O]&&T(e[O])}}),[]),o.a.createElement(o.a.Fragment,null,o.a.createElement("div",{className:"margin-bottom--"+(y||"md")},c&&o.a.createElement("div",{className:"margin-vert--sm"},c),v.length>1&&(i?o.a.createElement(h,Object(n.a)({changeSelectedValue:x,handleKeydown:q,placeholder:s,selectedValue:N,size:y,tabRefs:I},e)):o.a.createElement(m,Object(n.a)({changeSelectedValue:x,handleKeydown:q,selectedValue:N,tabRefs:I},e)))),l.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},466: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/bb89e1a0.c35682eb.js b/60296d59.d5a0b33f.js similarity index 93% rename from bb89e1a0.c35682eb.js rename to 60296d59.d5a0b33f.js index 2ada67d001..bb551287b5 100644 --- a/bb89e1a0.c35682eb.js +++ b/60296d59.d5a0b33f.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[214],{365: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(449)),l=a(461),c=a(464),i=a(448),s=a(453),b=(a(457),{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:"Integrate your application logs to Cloudwatch",permalink:"/guides/tutorial/cloudwatch-integration"}},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},448:function(e,t,a){"use strict";a(450);var n=a(0),o=a.n(n),r=a(447),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)}},452: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""}}})},453:function(e,t,a){"use strict";a(452);var n=a(0),o=a.n(n),r=a(448);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)}},454:function(e,t,a){"use strict";var n=a(1),o=a(0),r=a.n(o),l=a(39),c=a(458),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}))}},457:function(e,t,a){"use strict";var n=a(0),o=a.n(n),r=a(454),l=a(447),c=a.n(l);a(134);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)}},458:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},461:function(e,t,a){"use strict";var n=a(1),o=(a(465),a(462),a(52),a(29),a(22),a(21),a(0)),r=a.n(o),l=a(469),c=a(447),i=a.n(c),s=a(455),b=a.n(s),u=a(468),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])}},464: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([[117],{268: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(451)),l=a(463),c=a(466),i=a(450),s=a(455),b=(a(459),{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:"Integrate your application logs to Cloudwatch",permalink:"/guides/tutorial/cloudwatch-integration"}},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},450:function(e,t,a){"use strict";a(452);var n=a(0),o=a.n(n),r=a(449),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)}},454: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""}}})},455:function(e,t,a){"use strict";a(454);var n=a(0),o=a.n(n),r=a(450);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)}},456:function(e,t,a){"use strict";var n=a(1),o=a(0),r=a.n(o),l=a(39),c=a(460),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}))}},459:function(e,t,a){"use strict";var n=a(0),o=a.n(n),r=a(456),l=a(449),c=a.n(l);a(134);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)}},460:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},463:function(e,t,a){"use strict";var n=a(1),o=(a(467),a(464),a(52),a(29),a(22),a(21),a(0)),r=a.n(o),l=a(471),c=a(449),i=a.n(c),s=a(457),b=a.n(s),u=a(470),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])}},466: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.bea94ca5.js b/60ad046d.629984e7.js similarity index 73% rename from 60ad046d.bea94ca5.js rename to 60ad046d.629984e7.js index 51f4c8db9f..08ce1a1015 100644 --- a/60ad046d.bea94ca5.js +++ b/60ad046d.629984e7.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[117],{268: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([[118],{269: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.196ecb87.js b/6308ca27.b41984fb.js similarity index 93% rename from 6308ca27.196ecb87.js rename to 6308ca27.b41984fb.js index 1a6c101a0e..2fd6141b71 100644 --- a/6308ca27.196ecb87.js +++ b/6308ca27.b41984fb.js @@ -1,2 +1,2 @@ -/*! For license information please see 6308ca27.196ecb87.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 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(449)),o=(r(457),r(448)),s=(r(453),{last_modified_on:"2024-07-11",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:[]},{value:"Disabling the mirroring",id:"disabling-the-mirroring",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 Qovery is running on your infrastructure, it requires an image registry to store the images built via the Qovery CI and to mirror the images deployed from a 3rd party container registry."),Object(a.b)("p",null,"This ",Object(a.b)("inlineCode",{parentName:"p"},"mirroring registry")," is available and configurable within the Qovery interface"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/mirror-registry.png",alt:"Mirroring Repository"})),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,"In order to speed up the image build, we are using remote caches (available in AWS, GCP and Scaleway). It will avoid building the image from scratch, only the layers that changed will be built."),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,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."),Object(a.b)("h3",{id:"disabling-the-mirroring"},"Disabling the mirroring"),Object(a.b)("p",null,"If you want to reduce the deployment time by avoiding the mirroring operation, you can push your built images directly into the ",Object(a.b)("inlineCode",{parentName:"p"},"Mirroring registry"),". "),Object(a.b)("p",null,"Push the images in a image registry ",Object(a.b)("inlineCode",{parentName:"p"},"repository")," having the same name of the image you want to deploy. "),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Example on AWS")),Object(a.b)("p",null,"Let's say you have a container image called ",Object(a.b)("inlineCode",{parentName:"p"},"nginx")," that you build on your CI and the container registry associated with your cluster is ",Object(a.b)("a",Object(i.a)({parentName:"p"},{href:"https://32432542.dkr.ecr.eu-west-3.amazonaws.com"}),"https://32432542.dkr.ecr.eu-west-3.amazonaws.com"),". "),Object(a.b)("p",null,"You can push this image on the mirroring registry within the repository ",Object(a.b)("inlineCode",{parentName:"p"},"nginx"),", avoiding the mirroring operation: ",Object(a.b)("a",Object(i.a)({parentName:"p"},{href:"https://32432542.dkr.ecr.eu-west-3.amazonaws.com/nginx"}),"https://32432542.dkr.ecr.eu-west-3.amazonaws.com/nginx")))}m.isMDXComponent=!0},447: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}},452: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""}}})},453:function(e,t,r){"use strict";r(452);var i=r(0),n=r.n(i),a=r(448);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)}},454:function(e,t,r){"use strict";var i=r(1),n=r(0),a=r.n(n),o=r(39),s=r(458),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}))}},457:function(e,t,r){"use strict";var i=r(0),n=r.n(i),a=r(454),o=r(447),s=r.n(o);r(134);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)}},458: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.b41984fb.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[119],{270: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(451)),o=(r(459),r(450)),s=(r(455),{last_modified_on:"2024-07-11",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:[]},{value:"Disabling the mirroring",id:"disabling-the-mirroring",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 Qovery is running on your infrastructure, it requires an image registry to store the images built via the Qovery CI and to mirror the images deployed from a 3rd party container registry."),Object(a.b)("p",null,"This ",Object(a.b)("inlineCode",{parentName:"p"},"mirroring registry")," is available and configurable within the Qovery interface"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/mirror-registry.png",alt:"Mirroring Repository"})),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,"In order to speed up the image build, we are using remote caches (available in AWS, GCP and Scaleway). It will avoid building the image from scratch, only the layers that changed will be built."),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,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."),Object(a.b)("h3",{id:"disabling-the-mirroring"},"Disabling the mirroring"),Object(a.b)("p",null,"If you want to reduce the deployment time by avoiding the mirroring operation, you can push your built images directly into the ",Object(a.b)("inlineCode",{parentName:"p"},"Mirroring registry"),". "),Object(a.b)("p",null,"Push the images in a image registry ",Object(a.b)("inlineCode",{parentName:"p"},"repository")," having the same name of the image you want to deploy. "),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Example on AWS")),Object(a.b)("p",null,"Let's say you have a container image called ",Object(a.b)("inlineCode",{parentName:"p"},"nginx")," that you build on your CI and the container registry associated with your cluster is ",Object(a.b)("a",Object(i.a)({parentName:"p"},{href:"https://32432542.dkr.ecr.eu-west-3.amazonaws.com"}),"https://32432542.dkr.ecr.eu-west-3.amazonaws.com"),". "),Object(a.b)("p",null,"You can push this image on the mirroring registry within the repository ",Object(a.b)("inlineCode",{parentName:"p"},"nginx"),", avoiding the mirroring operation: ",Object(a.b)("a",Object(i.a)({parentName:"p"},{href:"https://32432542.dkr.ecr.eu-west-3.amazonaws.com/nginx"}),"https://32432542.dkr.ecr.eu-west-3.amazonaws.com/nginx")))}m.isMDXComponent=!0},449: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}},454: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""}}})},455:function(e,t,r){"use strict";r(454);var i=r(0),n=r.n(i),a=r(450);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)}},456:function(e,t,r){"use strict";var i=r(1),n=r(0),a=r.n(n),o=r(39),s=r(460),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}))}},459:function(e,t,r){"use strict";var i=r(0),n=r.n(i),a=r(456),o=r(449),s=r.n(o);r(134);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)}},460: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/6504a542.f7fba98f.js.LICENSE.txt b/6308ca27.b41984fb.js.LICENSE.txt similarity index 100% rename from 6504a542.f7fba98f.js.LICENSE.txt rename to 6308ca27.b41984fb.js.LICENSE.txt diff --git a/63ea0c72.a414f8a8.js b/63ea0c72.83479d14.js similarity index 74% rename from 63ea0c72.a414f8a8.js rename to 63ea0c72.83479d14.js index 95f27535f4..68c90b3a1b 100644 --- a/63ea0c72.a414f8a8.js +++ b/63ea0c72.83479d14.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[119],{270: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([[120],{271: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.f7fba98f.js b/6504a542.6c16d610.js similarity index 91% rename from 6504a542.f7fba98f.js rename to 6504a542.6c16d610.js index b323a11bbc..605c837f94 100644 --- a/6504a542.f7fba98f.js +++ b/6504a542.6c16d610.js @@ -1,2 +1,2 @@ -/*! For license information please see 6504a542.f7fba98f.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 u})),n.d(t,"default",(function(){return p}));var r=n(1),o=n(9),a=(n(0),n(449)),i=(n(456),n(453)),c=(n(448),{last_modified_on:"2024-06-11",$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:"Install Qovery on your Amazon Web Services account",permalink:"/guides/installation-guide/guide-amazon-web-services"}},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 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"}),"roadmap")),Object(a.b)("p",null,"Do you need any help? ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Reach us on our forum")))}p.isMDXComponent=!0},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(447),n(455)),i=n.n(a);n(133);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"),"."))}},459: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.6c16d610.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 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(451)),i=(n(458),n(455)),c=(n(450),{last_modified_on:"2024-06-11",$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:"Install Qovery on your Amazon Web Services account",permalink:"/guides/installation-guide/guide-amazon-web-services"}},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 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"}),"roadmap")),Object(a.b)("p",null,"Do you need any help? ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Reach us on our forum")))}p.isMDXComponent=!0},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(449),n(457)),i=n.n(a);n(133);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"),"."))}},461: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/66bbed7b.533e078b.js.LICENSE.txt b/6504a542.6c16d610.js.LICENSE.txt similarity index 100% rename from 66bbed7b.533e078b.js.LICENSE.txt rename to 6504a542.6c16d610.js.LICENSE.txt diff --git a/dea3d534.dc8cfedf.js b/66bbed7b.51085db1.js similarity index 94% rename from dea3d534.dc8cfedf.js rename to 66bbed7b.51085db1.js index 9181f2c666..8dc6f2a807 100644 --- a/dea3d534.dc8cfedf.js +++ b/66bbed7b.51085db1.js @@ -1,2 +1,2 @@ -/*! For license information please see dea3d534.dc8cfedf.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 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(449)),i=n(456),c=n(453),l=n(448),s={last_modified_on:"2023-12-20",$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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},455:function(e,t,n){"use strict";var a=n(459),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("&"):""}},456:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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.51085db1.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 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(451)),i=n(458),c=n(455),l=n(450),s={last_modified_on:"2023-12-20",$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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},457:function(e,t,n){"use strict";var a=n(461),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("&"):""}},458:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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.30818185.js.LICENSE.txt b/66bbed7b.51085db1.js.LICENSE.txt similarity index 100% rename from 672ba3d6.30818185.js.LICENSE.txt rename to 66bbed7b.51085db1.js.LICENSE.txt diff --git a/672ba3d6.30818185.js b/672ba3d6.8d7a51de.js similarity index 92% rename from 672ba3d6.30818185.js rename to 672ba3d6.8d7a51de.js index dba58bd450..4b9af95bb5 100644 --- a/672ba3d6.30818185.js +++ b/672ba3d6.8d7a51de.js @@ -1,2 +1,2 @@ -/*! For license information please see 672ba3d6.30818185.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[122],{273:function(e,t,a){"use strict";a.r(t);var n=a(0),r=a.n(n),o=a(474),i=a(471),c=a(586),l=a(460),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(i.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(c.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://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"))))))))}},447: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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),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(z,e))}))):null)}))),(m||i)&&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(Q,{alt:m.alt,url:d})):r.a.createElement(Q,{alt:m.alt,url:d})),r.a.createElement("small",null,i),r.a.createElement("br",null))))},F=a(486),Z=a(487),J=a(3);a(138);t.a=function(e){var t=Object(h.a)().siteConfig,a=void 0===t?{}:t,n=a.favicon,c=(a.tagline,a.title),l=a.themeConfig.image,s=a.url,m=e.children,u=e.title,d=e.noFooter,f=e.description,g=e.image,p=e.keywords,v=(e.permalink,e.version),b=u?u+" | "+c:c,E=g||l,y=s+Object(_.a)(E),w=Object(_.a)(n),N=Object(J.h)(),k=N?"https://docs.qovery.com"+(N.pathname.endsWith("/")?N.pathname:N.pathname+"/"):null;return r.a.createElement(Z.a,null,r.a.createElement(F.a,null,r.a.createElement(i.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}),p&&p.length&&r.a.createElement("meta",{name:"keywords",content:p.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(L,null),r.a.createElement("div",{className:"main-wrapper"},m),!d&&r.a.createElement(q,null)))}},474:function(e,t,a){"use strict";var n=a(9),r=a(0),o=a.n(r),i=a(447),c=a.n(i),l=a(460),s=(a(139),a(140)),m=a.n(s);t.a=function(e){return function(t){var a,r=t.id,i=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,i,o.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:c()("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"},"#"),i.children):o.a.createElement(e,i)}}},478:function(e,t,a){"use strict";var n=a(0),r=Object(n.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=r},503:function(e,t){var a,n,r=e.exports={};function o(){throw new Error("setTimeout has not been defined")}function i(){throw new Error("clearTimeout has not been defined")}function c(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:i}catch(e){n=i}}();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=c(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(503))},580: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 i=new Array(arguments.length),c=0;c0)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 i=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*i;case"days":case"day":case"d":return i*o;case"hours":case"hour":case"hrs":case"hr":case"h":return i*r;case"minutes":case"minute":case"mins":case"min":case"m":return i*n;case"seconds":case"second":case"secs":case"sec":case"s":return i*a;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return i;default:return}}(e);if("number"===l&&!1===isNaN(e))return t.long?i(c=e,o,"day")||i(c,r,"hour")||i(c,n,"minute")||i(c,a,"second")||c+" 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))}},582: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}))}},586:function(e,t,a){"use strict";a(472),a(473);var n=a(0),r=a.n(n),o=a(447),i=a.n(o),c=(a(58),a(21),a(578)),l=a.n(c),s=a(582),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 i="&EMAIL="+r+u(t),c=""+o+i;return m(c)};a(152),t.a=function(e){var t,a=e.block,o=e.buttonClass,c=e.center,l=e.description,s=e.subscriptionEnabled,m=e.size,u=e.width,f=Object(n.useState)(""),h=f[0],g=f[1],p=Object(n.useState)(!1),v=p[0],b=p[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:i()("mailing-list",(t={"mailing-list--block":a,"mailing-list--center":c},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:i()("mailing-list--form")},r.a.createElement("input",{onChange:function(e){return g(e.target.value)},className:i()("input","input--"+m),name:"email",placeholder:"you@email.com",type:"email",style:{width:u}}),r.a.createElement("button",{className:i()("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.8d7a51de.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[123],{274:function(e,t,a){"use strict";a.r(t);var n=a(0),r=a.n(n),o=a(476),i=a(473),c=a(588),l=a(462),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(i.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(c.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://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"))))))))}},449: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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),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(z,e))}))):null)}))),(m||i)&&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(Q,{alt:m.alt,url:d})):r.a.createElement(Q,{alt:m.alt,url:d})),r.a.createElement("small",null,i),r.a.createElement("br",null))))},F=a(488),Z=a(489),J=a(3);a(138);t.a=function(e){var t=Object(h.a)().siteConfig,a=void 0===t?{}:t,n=a.favicon,c=(a.tagline,a.title),l=a.themeConfig.image,s=a.url,m=e.children,u=e.title,d=e.noFooter,f=e.description,g=e.image,p=e.keywords,v=(e.permalink,e.version),b=u?u+" | "+c:c,E=g||l,y=s+Object(_.a)(E),w=Object(_.a)(n),N=Object(J.h)(),k=N?"https://docs.qovery.com"+(N.pathname.endsWith("/")?N.pathname:N.pathname+"/"):null;return r.a.createElement(Z.a,null,r.a.createElement(F.a,null,r.a.createElement(i.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}),p&&p.length&&r.a.createElement("meta",{name:"keywords",content:p.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(L,null),r.a.createElement("div",{className:"main-wrapper"},m),!d&&r.a.createElement(q,null)))}},476:function(e,t,a){"use strict";var n=a(9),r=a(0),o=a.n(r),i=a(449),c=a.n(i),l=a(462),s=(a(139),a(140)),m=a.n(s);t.a=function(e){return function(t){var a,r=t.id,i=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,i,o.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:c()("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"},"#"),i.children):o.a.createElement(e,i)}}},480:function(e,t,a){"use strict";var n=a(0),r=Object(n.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=r},505:function(e,t){var a,n,r=e.exports={};function o(){throw new Error("setTimeout has not been defined")}function i(){throw new Error("clearTimeout has not been defined")}function c(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:i}catch(e){n=i}}();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=c(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(505))},582: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 i=new Array(arguments.length),c=0;c0)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 i=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*i;case"days":case"day":case"d":return i*o;case"hours":case"hour":case"hrs":case"hr":case"h":return i*r;case"minutes":case"minute":case"mins":case"min":case"m":return i*n;case"seconds":case"second":case"secs":case"sec":case"s":return i*a;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return i;default:return}}(e);if("number"===l&&!1===isNaN(e))return t.long?i(c=e,o,"day")||i(c,r,"hour")||i(c,n,"minute")||i(c,a,"second")||c+" 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))}},584: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}))}},588:function(e,t,a){"use strict";a(474),a(475);var n=a(0),r=a.n(n),o=a(449),i=a.n(o),c=(a(58),a(21),a(580)),l=a.n(c),s=a(584),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 i="&EMAIL="+r+u(t),c=""+o+i;return m(c)};a(152),t.a=function(e){var t,a=e.block,o=e.buttonClass,c=e.center,l=e.description,s=e.subscriptionEnabled,m=e.size,u=e.width,f=Object(n.useState)(""),h=f[0],g=f[1],p=Object(n.useState)(!1),v=p[0],b=p[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:i()("mailing-list",(t={"mailing-list--block":a,"mailing-list--center":c},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:i()("mailing-list--form")},r.a.createElement("input",{onChange:function(e){return g(e.target.value)},className:i()("input","input--"+m),name:"email",placeholder:"you@email.com",type:"email",style:{width:u}}),r.a.createElement("button",{className:i()("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/68b95634.25314847.js.LICENSE.txt b/672ba3d6.8d7a51de.js.LICENSE.txt similarity index 100% rename from 68b95634.25314847.js.LICENSE.txt rename to 672ba3d6.8d7a51de.js.LICENSE.txt diff --git a/6852f5b3.beedb690.js b/6852f5b3.6946193a.js similarity index 72% rename from 6852f5b3.beedb690.js rename to 6852f5b3.6946193a.js index 3c11e8ec8c..b225edf880 100644 --- a/6852f5b3.beedb690.js +++ b/6852f5b3.6946193a.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[123],{274:function(i){i.exports=JSON.parse('{"category":{"name":"installation-guide","title":"Installation Guide","description":null,"permalink":"/guides/installation-guide"}}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[124],{275:function(i){i.exports=JSON.parse('{"category":{"name":"installation-guide","title":"Installation Guide","description":null,"permalink":"/guides/installation-guide"}}')}}]); \ No newline at end of file diff --git a/68b95634.25314847.js b/68b95634.0ba07781.js similarity index 91% rename from 68b95634.25314847.js rename to 68b95634.0ba07781.js index ff7665ae83..6367629390 100644 --- a/68b95634.25314847.js +++ b/68b95634.0ba07781.js @@ -1,2 +1,2 @@ -/*! For license information please see 68b95634.25314847.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[124],{275: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(449)),i=(r(466),r(456),r(453),r(448),r(577),{last_modified_on:"2024-07-29",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 a DevOps Automation Platform that eliminates your DevOps hiring needs. Provision and maintain a secure and compliant infrastructure in hours - not months!"),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 DevOps Automation 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},447: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}},452: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""}}})},453:function(e,t,r){"use strict";r(452);var n=r(0),a=r.n(n),o=r(448);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)}},455:function(e,t,r){"use strict";var n=r(459),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("&"):""}},456:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(447),r(455)),i=r.n(o);r(133);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"),"."))}},459:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}},577:function(e,t,r){"use strict";r(0)}}]); \ No newline at end of file +/*! For license information please see 68b95634.0ba07781.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[125],{276: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(451)),i=(r(468),r(458),r(455),r(450),r(579),{last_modified_on:"2024-07-29",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 a DevOps Automation Platform that eliminates your DevOps hiring needs. Provision and maintain a secure and compliant infrastructure in hours - not months!"),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 DevOps Automation 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},449: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}},454: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""}}})},455:function(e,t,r){"use strict";r(454);var n=r(0),a=r.n(n),o=r(450);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)}},457:function(e,t,r){"use strict";var n=r(461),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("&"):""}},458:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(449),r(457)),i=r.n(o);r(133);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"),"."))}},461:function(e,t,r){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}},579:function(e,t,r){"use strict";r(0)}}]); \ No newline at end of file diff --git a/68c0e7f9.e8e73e0b.js.LICENSE.txt b/68b95634.0ba07781.js.LICENSE.txt similarity index 100% rename from 68c0e7f9.e8e73e0b.js.LICENSE.txt rename to 68b95634.0ba07781.js.LICENSE.txt diff --git a/68c0e7f9.e8e73e0b.js b/68c0e7f9.e5547931.js similarity index 88% rename from 68c0e7f9.e8e73e0b.js rename to 68c0e7f9.e5547931.js index 981718bc70..46364662de 100644 --- a/68c0e7f9.e8e73e0b.js +++ b/68c0e7f9.e5547931.js @@ -1,2 +1,2 @@ -/*! For license information please see 68c0e7f9.e8e73e0b.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 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(449)),i=(n(456),n(453),n(448)),c={last_modified_on:"2023-12-27",$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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(447),n(455)),i=n.n(a);n(133);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"),"."))}},459: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.e5547931.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 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(451)),i=(n(458),n(455),n(450)),c={last_modified_on:"2023-12-27",$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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(449),n(457)),i=n.n(a);n(133);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"),"."))}},461: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/6b0e113a.90abc200.js.LICENSE.txt b/68c0e7f9.e5547931.js.LICENSE.txt similarity index 100% rename from 6b0e113a.90abc200.js.LICENSE.txt rename to 68c0e7f9.e5547931.js.LICENSE.txt diff --git a/6b0e113a.90abc200.js b/6b0e113a.4a0babec.js similarity index 88% rename from 6b0e113a.90abc200.js rename to 6b0e113a.4a0babec.js index 019b26d843..f49a71b182 100644 --- a/6b0e113a.90abc200.js +++ b/6b0e113a.4a0babec.js @@ -1,2 +1,2 @@ -/*! For license information please see 6b0e113a.90abc200.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 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(449)),o=n(448),c=(n(457),n(453),{last_modified_on:"2024-06-04",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)("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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),i=n.n(r),a=n(448);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)}},454:function(e,t,n){"use strict";var r=n(1),i=n(0),a=n.n(i),o=n(39),c=n(458),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}))}},457:function(e,t,n){"use strict";var r=n(0),i=n.n(r),a=n(454),o=n(447),c=n.n(o);n(134);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)}},458: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 6b0e113a.4a0babec.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 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(451)),o=n(450),c=(n(459),n(455),{last_modified_on:"2024-06-04",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)("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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),i=n.n(r),a=n(450);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)}},456:function(e,t,n){"use strict";var r=n(1),i=n(0),a=n.n(i),o=n(39),c=n(460),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}))}},459:function(e,t,n){"use strict";var r=n(0),i=n.n(r),a=n(456),o=n(449),c=n.n(o);n(134);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)}},460: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/6b7a52aa.aa9958dd.js.LICENSE.txt b/6b0e113a.4a0babec.js.LICENSE.txt similarity index 100% rename from 6b7a52aa.aa9958dd.js.LICENSE.txt rename to 6b0e113a.4a0babec.js.LICENSE.txt diff --git a/8d146bfd.b51b9e03.js b/6b7a52aa.4ae1cc4e.js similarity index 96% rename from 8d146bfd.b51b9e03.js rename to 6b7a52aa.4ae1cc4e.js index c1e73cd9e0..18e85c2e67 100644 --- a/8d146bfd.b51b9e03.js +++ b/6b7a52aa.4ae1cc4e.js @@ -1,2 +1,2 @@ -/*! For license information please see 8d146bfd.b51b9e03.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[151],{303: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(449)),i=n(456),c=n(448),l=n(453),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var o=n(0),r=n.n(o),a=n(448);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)}},455:function(e,t,n){"use strict";var o=n(459),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("&"):""}},456:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(447),n(455)),i=n.n(a);n(133);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"),"."))}},459: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.4ae1cc4e.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 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(451)),i=n(458),c=n(450),l=n(455),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var o=n(0),r=n.n(o),a=n(450);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)}},457:function(e,t,n){"use strict";var o=n(461),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("&"):""}},458:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(449),n(457)),i=n.n(a);n(133);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"),"."))}},461: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/6ebd4d49.2bd448ab.js.LICENSE.txt b/6b7a52aa.4ae1cc4e.js.LICENSE.txt similarity index 100% rename from 6ebd4d49.2bd448ab.js.LICENSE.txt rename to 6b7a52aa.4ae1cc4e.js.LICENSE.txt diff --git a/6ce627d6.f848a98d.js b/6ce627d6.0a93740f.js similarity index 98% rename from 6ce627d6.f848a98d.js rename to 6ce627d6.0a93740f.js index e2be6fd25b..4d2916e862 100644 --- a/6ce627d6.f848a98d.js +++ b/6ce627d6.0a93740f.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[128],{279: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(449)),l=a(448),i=a(464),c=a(461),b=a(453),u={last_modified_on:"2024-05-16",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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)(l.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"This guide also work for migrating your application from Heroku to GCP, Azure, Scaleway and ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/"}),"all cloud provider")," supported by Qovery.")),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/installation-guide/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,"Absolutely, you can connect directly to your application with a shell by clicking on the Qovery cloud shell button (1):"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/qovery_cloud_shell.png",alt:"Qovery Cloud Shell"})),Object(r.b)("p",null,"Then you just have to select the pod (2) and the container (3)."),Object(r.b)("p",null,"You can also check out our ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/#shell"}),"CLI")," and the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery shell")," command."),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},448:function(e,t,a){"use strict";a(450);var o=a(0),n=a.n(o),r=a(447),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)}},452: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""}}})},453:function(e,t,a){"use strict";a(452);var o=a(0),n=a.n(o),r=a(448);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)}},461:function(e,t,a){"use strict";var o=a(1),n=(a(465),a(462),a(52),a(29),a(22),a(21),a(0)),r=a.n(n),l=a(469),i=a(447),c=a.n(i),b=a(455),u=a.n(b),s=a(468),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])}},464: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([[129],{280: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(451)),l=a(450),i=a(466),c=a(463),b=a(455),u={last_modified_on:"2024-05-16",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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)(l.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"This guide also work for migrating your application from Heroku to GCP, Azure, Scaleway and ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/"}),"all cloud provider")," supported by Qovery.")),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/installation-guide/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,"Absolutely, you can connect directly to your application with a shell by clicking on the Qovery cloud shell button (1):"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/qovery_cloud_shell.png",alt:"Qovery Cloud Shell"})),Object(r.b)("p",null,"Then you just have to select the pod (2) and the container (3)."),Object(r.b)("p",null,"You can also check out our ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/cli/#shell"}),"CLI")," and the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery shell")," command."),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},450:function(e,t,a){"use strict";a(452);var o=a(0),n=a.n(o),r=a(449),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)}},454: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""}}})},455:function(e,t,a){"use strict";a(454);var o=a(0),n=a.n(o),r=a(450);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)}},463:function(e,t,a){"use strict";var o=a(1),n=(a(467),a(464),a(52),a(29),a(22),a(21),a(0)),r=a.n(n),l=a(471),i=a(449),c=a.n(i),b=a(457),u=a.n(b),s=a(470),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])}},466: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.2bd448ab.js b/6ebd4d49.66bcc13b.js similarity index 92% rename from 6ebd4d49.2bd448ab.js rename to 6ebd4d49.66bcc13b.js index c5fd24ac4e..fab7ea91bd 100644 --- a/6ebd4d49.2bd448ab.js +++ b/6ebd4d49.66bcc13b.js @@ -1,2 +1,2 @@ -/*! For license information please see 6ebd4d49.2bd448ab.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[129],{280: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(449)),r=(n(457),n(448)),l=(n(453),{last_modified_on:"2024-02-28",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,"If you have several pods within your application, you have the possiblity to filter the logs by pod. "),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/live_logs_filtered.png",alt:"Log content"})),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var o=n(0),i=n.n(o),a=n(448);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)}},454:function(e,t,n){"use strict";var o=n(1),i=n(0),a=n.n(i),r=n(39),l=n(458),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}))}},457:function(e,t,n){"use strict";var o=n(0),i=n.n(o),a=n(454),r=n(447),l=n.n(r);n(134);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)}},458: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.66bcc13b.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[130],{281: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(451)),r=(n(459),n(450)),l=(n(455),{last_modified_on:"2024-02-28",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,"If you have several pods within your application, you have the possiblity to filter the logs by pod. "),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/deployment/live_logs_filtered.png",alt:"Log content"})),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var o=n(0),i=n.n(o),a=n(450);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)}},456:function(e,t,n){"use strict";var o=n(1),i=n(0),a=n.n(i),r=n(39),l=n(460),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}))}},459:function(e,t,n){"use strict";var o=n(0),i=n.n(o),a=n(456),r=n(449),l=n.n(r);n(134);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)}},460: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/6f4ba85a.c4e01b6a.js.LICENSE.txt b/6ebd4d49.66bcc13b.js.LICENSE.txt similarity index 100% rename from 6f4ba85a.c4e01b6a.js.LICENSE.txt rename to 6ebd4d49.66bcc13b.js.LICENSE.txt diff --git a/6f4ba85a.c4e01b6a.js b/6f4ba85a.fe80187f.js similarity index 89% rename from 6f4ba85a.c4e01b6a.js rename to 6f4ba85a.fe80187f.js index ea7ec6ae11..82d12a70e9 100644 --- a/6f4ba85a.c4e01b6a.js +++ b/6f4ba85a.fe80187f.js @@ -1,2 +1,2 @@ -/*! For license information please see 6f4ba85a.c4e01b6a.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[130],{281: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(449)),i=(n(456),n(448),{last_modified_on:"2024-01-10",title:"FAQ",description:"Discover the most frequently asked questions about Qovery BYOK"}),c={id:"getting-started/install-qovery/kubernetes/faq",title:"FAQ",description:"Discover the most frequently asked questions about Qovery BYOK",source:"@site/docs/getting-started/install-qovery/kubernetes/faq.md",permalink:"/docs/getting-started/install-qovery/kubernetes/faq",sidebar:"docs",previous:{title:"Validate the installation",permalink:"/docs/getting-started/install-qovery/kubernetes/validate-installation"},next:{title:"Deploy my application",permalink:"/docs/getting-started/deploy-my-app"}},u=[{value:"FAQ",id:"faq",children:[{value:"I have a non-covered use case. What should I do?",id:"i-have-a-non-covered-use-case-what-should-i-do",children:[]},{value:"Can I host the Qovery control plane on my own?",id:"can-i-host-the-qovery-control-plane-on-my-own",children:[]}]}],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"}),Object(a.b)("h2",{id:"faq"},"FAQ"),Object(a.b)("h3",{id:"i-have-a-non-covered-use-case-what-should-i-do"},"I have a non-covered use case. What should I do?"),Object(a.b)("p",null,"Please ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/contact"}),"contact us"),". We will be happy to help you."),Object(a.b)("h3",{id:"can-i-host-the-qovery-control-plane-on-my-own"},"Can I host the Qovery control plane on my own?"),Object(a.b)("p",null,"At the moment, you can't. But please ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/contact"}),"contact us")," to discuss it. We will be happy to help you."))}l.isMDXComponent=!0},447: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,y=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;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 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}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(447),n(455)),i=n.n(a);n(133);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"),"."))}},459: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 6f4ba85a.fe80187f.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 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(451)),i=(n(458),n(450),{last_modified_on:"2024-01-10",title:"FAQ",description:"Discover the most frequently asked questions about Qovery BYOK"}),c={id:"getting-started/install-qovery/kubernetes/faq",title:"FAQ",description:"Discover the most frequently asked questions about Qovery BYOK",source:"@site/docs/getting-started/install-qovery/kubernetes/faq.md",permalink:"/docs/getting-started/install-qovery/kubernetes/faq",sidebar:"docs",previous:{title:"Validate the installation",permalink:"/docs/getting-started/install-qovery/kubernetes/validate-installation"},next:{title:"Deploy my application",permalink:"/docs/getting-started/deploy-my-app"}},u=[{value:"FAQ",id:"faq",children:[{value:"I have a non-covered use case. What should I do?",id:"i-have-a-non-covered-use-case-what-should-i-do",children:[]},{value:"Can I host the Qovery control plane on my own?",id:"can-i-host-the-qovery-control-plane-on-my-own",children:[]}]}],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"}),Object(a.b)("h2",{id:"faq"},"FAQ"),Object(a.b)("h3",{id:"i-have-a-non-covered-use-case-what-should-i-do"},"I have a non-covered use case. What should I do?"),Object(a.b)("p",null,"Please ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/contact"}),"contact us"),". We will be happy to help you."),Object(a.b)("h3",{id:"can-i-host-the-qovery-control-plane-on-my-own"},"Can I host the Qovery control plane on my own?"),Object(a.b)("p",null,"At the moment, you can't. But please ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.qovery.com/contact"}),"contact us")," to discuss it. We will be happy to help you."))}l.isMDXComponent=!0},449: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,y=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;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 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}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(449),n(457)),i=n.n(a);n(133);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"),"."))}},461: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/73d96058.27e627ee.js.LICENSE.txt b/6f4ba85a.fe80187f.js.LICENSE.txt similarity index 100% rename from 73d96058.27e627ee.js.LICENSE.txt rename to 6f4ba85a.fe80187f.js.LICENSE.txt diff --git a/7278678a.7b410ea0.js b/7278678a.b5423039.js similarity index 96% rename from 7278678a.7b410ea0.js rename to 7278678a.b5423039.js index 9f09ceb3f9..3f50ef4be3 100644 --- a/7278678a.7b410ea0.js +++ b/7278678a.b5423039.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[131],{282: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(449)),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},449: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=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):l({},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)}},y=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(n),y=r,d=p["".concat(i,".").concat(y)]||p[y]||f[y]||o;return n?a.a.createElement(d,l({ref:t},u,{components:n})):a.a.createElement(d,l({ref:t},u))}));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]=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: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:a(c,n);u>l;)t[l++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see 73d96058.f67e3038.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[134],{285: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 p}));var r=n(1),a=n(9),o=(n(0),n(451)),i=n(450),l={last_modified_on:"2024-01-02",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Scaleway account",description:"Learn how to install Qovery on your Scaleway account",series_position:3,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: scaleway"]},c={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery on your Scaleway account",description:"Learn how to install Qovery on your Scaleway account",permalink:"/guides/installation-guide/guide-scaleway",readingTime:"1 min read",seriesPosition:3,source:"@site/guides/installation-guide/guide-scaleway.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: scaleway",permalink:"/guides/tags/installation-guide-scaleway"}],title:"Install Qovery on your Scaleway account",truncated:!1,prevItem:{title:"Install Qovery your Google Cloud Platform account",permalink:"/guides/installation-guide/guide-google-cloud-platform"},nextItem:{title:"Install Qovery on your Kubernetes cluster",permalink:"/guides/installation-guide/guide-kubernetes"}},u=[],s={rightToc:u};function p(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)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Access our new installation guide of Qovery on Scaleway ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/"}),"here"))))}p.isMDXComponent=!0},449: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):l({},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)}},y=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(n),y=r,d=p["".concat(i,".").concat(y)]||p[y]||f[y]||o;return n?a.a.createElement(d,l({ref:t},u,{components:n})):a.a.createElement(d,l({ref:t},u))}));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]=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: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:a(c,n);u>l;)t[l++]=e;return t}}}]); \ No newline at end of file diff --git a/7952d159.2eeb0fc5.js.LICENSE.txt b/73d96058.f67e3038.js.LICENSE.txt similarity index 100% rename from 7952d159.2eeb0fc5.js.LICENSE.txt rename to 73d96058.f67e3038.js.LICENSE.txt diff --git a/766a314f.a54f32c4.js b/766a314f.a54f32c4.js new file mode 100644 index 0000000000..6378684846 --- /dev/null +++ b/766a314f.a54f32c4.js @@ -0,0 +1,2 @@ +/*! For license information please see 766a314f.a54f32c4.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[135],{286: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 u}));var r=n(1),a=n(9),o=(n(0),n(451)),i=(n(450),n(458),n(455),{last_modified_on:"2024-08-09",$schema:"/.meta/.schemas/guides.json",title:"Deploy a DaemonSet in a Karpenter context",description:"How to ensure your DaemonSet is well deployed when you are using Karpenter.",author_github:"https://github.com/baalooos",tags:["type: tutorial","technology: qovery","installation_guide: aws"],hide_pagination:!0}),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 a DaemonSet in a Karpenter context",description:"How to ensure your DaemonSet is well deployed when you are using Karpenter.",permalink:"/guides/advanced/deploy-daemonset-with-karpenter",readingTime:"4 min read",source:"@site/guides/advanced/deploy-daemonset-with-karpenter.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"},{label:"installation_guide: aws",permalink:"/guides/tags/installation-guide-aws"}],title:"Deploy a DaemonSet in a Karpenter context",truncated:!1,prevItem:{title:"Customizing Preview URL with Qovery CLI",permalink:"/guides/tutorial/customizing-preview-url-with-qovery-cli"},nextItem:{title:"Deploy API Gateway",permalink:"/guides/advanced/deploy-api-gateway"}},s=[{value:"What is a DaemonSet?",id:"what-is-a-daemonset",children:[]},{value:"What is the problem?",id:"what-is-the-problem",children:[]},{value:"How to resolve it?",id:"how-to-resolve-it",children:[{value:"What is a Priority Class?",id:"what-is-a-priority-class",children:[]},{value:"Deploy a new Priority Class using Helm",id:"deploy-a-new-priority-class-using-helm",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],c={rightToc:s};function u(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(o.b)("wrapper",Object(r.a)({},c,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://karpenter.sh/"}),"Karpenter")," is a great way to cut your AWS bill. It provides an easy and flexible way to scale and optimize your resource consumption. But there is a known ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/kubernetes-sigs/karpenter/issues/731"}),"issue")," with capacity planning when you deploy DaemonSets. In this guide, I will present the issue and explain how to avoid it by using Priority Class."),Object(o.b)("h2",{id:"what-is-a-daemonset"},"What is a DaemonSet?"),Object(o.b)("p",null,"A DaemonSet in Kubernetes is a specialized controller used to ensure that a copy of a particular pod runs on all nodes in a cluster. It is particularly useful for deploying background tasks or system-level services that need to run on every node, such as log collectors, monitoring agents, or network components."),Object(o.b)("p",null,"When nodes are added to the cluster, the DaemonSet automatically schedules the specified pod on the new nodes, ensuring consistent deployment across the entire infrastructure. Similarly, when nodes are removed, the DaemonSet takes care of cleaning up the pods that were running on those nodes."),Object(o.b)("p",null,"This makes DaemonSets a powerful tool for maintaining uniformity and reliability in the operation of essential services across a Kubernetes cluster."),Object(o.b)("h2",{id:"what-is-the-problem"},"What is the problem?"),Object(o.b)("p",null,"There is a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/kubernetes-sigs/karpenter/issues/731"}),"known issue")," with Karpenter and DaemonSets when scaling nodes. DaemonSets ensure a copy of a pod runs on every node, consuming additional resources that Karpenter does not consider, leading to potential resource contention and under-provisioned nodes."),Object(o.b)("p",null,"This forces operators to over-provision their nodes, resulting in inefficient resource utilization and higher costs. While the Kubernetes community and Karpenter developers are working on solutions, users currently need to manually adjust resource allocations and monitor node utilization to mitigate these issues."),Object(o.b)("p",null,"A way to resolve this problem is to use a Priority Class and attach it to the DaemonSet we are creating."),Object(o.b)("h2",{id:"how-to-resolve-it"},"How to resolve it?"),Object(o.b)("h3",{id:"what-is-a-priority-class"},"What is a Priority Class?"),Object(o.b)("p",null,"A PriorityClass in Kubernetes is a resource used to assign a priority level to pods. This resource helps the scheduler make decisions during resource contention."),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Higher-priority pods are scheduled before lower-priority ones"),Object(o.b)("li",{parentName:"ul"},"In case of resource shortages, lower-priority pods may be preempted (evicted) to make room for higher-priority pods.")),Object(o.b)("p",null,"This ensures that critical workloads receive the necessary resources to run effectively."),Object(o.b)("h3",{id:"deploy-a-new-priority-class-using-helm"},"Deploy a new Priority Class using Helm"),Object(o.b)("p",null,"I created a ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/baalooos/karpenter-daemonset-priority-class"}),"simple repository")," you can clone to follow along."),Object(o.b)("p",null,"Create the karpenter-priority-class service in the Qovery environment where you want to deploy your DaemonSet by following ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/"}),"this documentation")," and these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"General:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Service name: ",Object(o.b)("inlineCode",{parentName:"li"},"karpenter-priority-class")),Object(o.b)("li",{parentName:"ul"},"Source:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Helm source: ",Object(o.b)("inlineCode",{parentName:"li"},"Git Provider")),Object(o.b)("li",{parentName:"ul"},"Git repository: ",Object(o.b)("inlineCode",{parentName:"li"},"Github")," (Change if you are not using GitHub)"),Object(o.b)("li",{parentName:"ul"},"Repository: ",Object(o.b)("inlineCode",{parentName:"li"},"Baalooos/karpenter-daemonset-priority-class")," (Replace by the name of your repository)"),Object(o.b)("li",{parentName:"ul"},"Branch: ",Object(o.b)("inlineCode",{parentName:"li"},"main")),Object(o.b)("li",{parentName:"ul"},"Root application path: ",Object(o.b)("inlineCode",{parentName:"li"},"/")),Object(o.b)("li",{parentName:"ul"},"Allow cluster-wide resources \u2714\ufe0f")))))),Object(o.b)("p",null,"Click on Continue"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Values override as file:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"File source: ",Object(o.b)("inlineCode",{parentName:"li"},"Git repository")),Object(o.b)("li",{parentName:"ul"},"Git repository: ",Object(o.b)("inlineCode",{parentName:"li"},"Github")," (Change if you are not using GitHub)"),Object(o.b)("li",{parentName:"ul"},"Repository: ",Object(o.b)("inlineCode",{parentName:"li"},"Baalooos/karpenter-daemonset-priority-class")," (Replace by the name of your repository)"),Object(o.b)("li",{parentName:"ul"},"Branch: ",Object(o.b)("inlineCode",{parentName:"li"},"main")),Object(o.b)("li",{parentName:"ul"},"Override path: ",Object(o.b)("inlineCode",{parentName:"li"},"/values.yaml"))))),Object(o.b)("p",null,"Then, you can:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"deploy this helm service to add the priority class on your cluster"),Object(o.b)("li",{parentName:"ul"},"Modify your DaemonSet configuration to use the new priority class an redeploy it")),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"Even if Karpenter is a great way of reducing your AWS bill, sometimes you will have to do some manual lifting. This issue is a good example. A single Priority Class is enough to avoid a complex resource allocation problem."))}u.isMDXComponent=!0},449: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 c=a.a.createContext({}),u=function(e){var t=a.a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},p=function(e){var t=u(e.components);return a.a.createElement(c.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,c=s(e,["components","mdxType","originalType","parentName"]),p=u(n),b=r,m=p["".concat(i,".").concat(b)]||p[b]||d[b]||o;return n?a.a.createElement(m,l({ref:t},c,{components:n})):a.a.createElement(m,l({ref:t},c))}));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 l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:r,i[1]=l;for(var c=2;c1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,c=void 0===s?n:a(s,n);c>l;)t[l++]=e;return t}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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),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:c,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"),"."))}},461: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/7aa59ca3.8f5ea392.js.LICENSE.txt b/766a314f.a54f32c4.js.LICENSE.txt similarity index 100% rename from 7aa59ca3.8f5ea392.js.LICENSE.txt rename to 766a314f.a54f32c4.js.LICENSE.txt diff --git a/7952d159.2eeb0fc5.js b/7952d159.7e807abb.js similarity index 93% rename from 7952d159.2eeb0fc5.js rename to 7952d159.7e807abb.js index 950263a77d..53df3461a4 100644 --- a/7952d159.2eeb0fc5.js +++ b/7952d159.7e807abb.js @@ -1,2 +1,2 @@ -/*! For license information please see 7952d159.2eeb0fc5.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[134],{285: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(449)),o=n(448),c=n(453),l=(n(457),{last_modified_on:"2024-07-30",$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/#custom-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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),i=n.n(a),r=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),i=n(0),r=n.n(i),o=n(39),c=n(458),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}))}},457:function(e,t,n){"use strict";var a=n(0),i=n.n(a),r=n(454),o=n(447),c=n.n(o);n(134);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)}},458: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.7e807abb.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[136],{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 p})),n.d(t,"default",(function(){return b}));var a=n(1),i=n(9),r=(n(0),n(451)),o=n(450),c=n(455),l=(n(459),{last_modified_on:"2024-07-30",$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/#custom-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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),i=n.n(a),r=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),i=n(0),r=n.n(i),o=n(39),c=n(460),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}))}},459:function(e,t,n){"use strict";var a=n(0),i=n.n(a),r=n(456),o=n(449),c=n.n(o);n(134);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)}},460: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/7cc8f9b8.54df3b52.js.LICENSE.txt b/7952d159.7e807abb.js.LICENSE.txt similarity index 100% rename from 7cc8f9b8.54df3b52.js.LICENSE.txt rename to 7952d159.7e807abb.js.LICENSE.txt diff --git a/de0a75d9.01fb1818.js b/7aa59ca3.b75d33b6.js similarity index 92% rename from de0a75d9.01fb1818.js rename to 7aa59ca3.b75d33b6.js index 5653bcba86..b274509d2c 100644 --- a/de0a75d9.01fb1818.js +++ b/7aa59ca3.b75d33b6.js @@ -1,2 +1,2 @@ -/*! For license information please see de0a75d9.01fb1818.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 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(449)),c=n(456),i=n(448),l=n(453),u=(n(457),{last_modified_on:"2024-01-05",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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. You can retrieve the Kubeconfig of your cluster directly from the Qovery interface by following the procedure "Get your cluster kubeconfig file" ',Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#performing-actions-on-your-clusters"}),"within this section"),".")),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var o=n(0),a=n.n(o),r=n(448);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)}},454:function(e,t,n){"use strict";var o=n(1),a=n(0),r=n.n(a),c=n(39),i=n(458),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}))}},455:function(e,t,n){"use strict";var o=n(459),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("&"):""}},456:function(e,t,n){"use strict";var o=n(0),a=n.n(o),r=(n(447),n(455)),c=n.n(r);n(133);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"),"."))}},457:function(e,t,n){"use strict";var o=n(0),a=n.n(o),r=n(454),c=n(447),i=n.n(c);n(134);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)}},458:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},459: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.b75d33b6.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[137],{288: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(451)),c=n(458),i=n(450),l=n(455),u=(n(459),{last_modified_on:"2024-01-05",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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. You can retrieve the Kubeconfig of your cluster directly from the Qovery interface by following the procedure "Get your cluster kubeconfig file" ',Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#performing-actions-on-your-clusters"}),"within this section"),".")),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var o=n(0),a=n.n(o),r=n(450);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)}},456:function(e,t,n){"use strict";var o=n(1),a=n(0),r=n.n(a),c=n(39),i=n(460),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}))}},457:function(e,t,n){"use strict";var o=n(461),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("&"):""}},458:function(e,t,n){"use strict";var o=n(0),a=n.n(o),r=(n(449),n(457)),c=n.n(r);n(133);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"),"."))}},459:function(e,t,n){"use strict";var o=n(0),a=n.n(o),r=n(456),c=n(449),i=n.n(c);n(134);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)}},460:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},461: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/7df50433.35cc68c8.js.LICENSE.txt b/7aa59ca3.b75d33b6.js.LICENSE.txt similarity index 100% rename from 7df50433.35cc68c8.js.LICENSE.txt rename to 7aa59ca3.b75d33b6.js.LICENSE.txt diff --git a/7cc8f9b8.54df3b52.js b/7cc8f9b8.4e827f65.js similarity index 89% rename from 7cc8f9b8.54df3b52.js rename to 7cc8f9b8.4e827f65.js index 68d49301e8..60e8d16b18 100644 --- a/7cc8f9b8.54df3b52.js +++ b/7cc8f9b8.4e827f65.js @@ -1,2 +1,2 @@ -/*! For license information please see 7cc8f9b8.54df3b52.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[136],{287: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 p}));var r=n(1),a=n(9),o=(n(0),n(449)),i=n(448),l={last_modified_on:"2024-01-02",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Scaleway account",description:"Learn how to install Qovery on your Scaleway account",series_position:3,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: scaleway"]},c={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery on your Scaleway account",description:"Learn how to install Qovery on your Scaleway account",permalink:"/guides/installation-guide/guide-scaleway",readingTime:"1 min read",seriesPosition:3,source:"@site/guides/installation-guide/guide-scaleway.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: scaleway",permalink:"/guides/tags/installation-guide-scaleway"}],title:"Install Qovery on your Scaleway account",truncated:!1,prevItem:{title:"Install Qovery your Google Cloud Platform account",permalink:"/guides/installation-guide/guide-google-cloud-platform"},nextItem:{title:"Install Qovery on your Kubernetes cluster",permalink:"/guides/installation-guide/guide-kubernetes"}},u=[],s={rightToc:u};function p(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)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Access our new installation guide of Qovery on Scaleway ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/"}),"here"))))}p.isMDXComponent=!0},447: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):l({},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)}},y=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(n),y=r,d=p["".concat(i,".").concat(y)]||p[y]||f[y]||o;return n?a.a.createElement(d,l({ref:t},u,{components:n})):a.a.createElement(d,l({ref:t},u))}));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]=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: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:a(c,n);u>l;)t[l++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see 7cc8f9b8.4e827f65.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[138],{289: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 p}));var r=n(1),a=n(9),o=(n(0),n(451)),i=n(450),l={last_modified_on:"2024-01-02",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Scaleway account",description:"Learn how to install Qovery on your Scaleway account",series_position:3,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: scaleway"]},c={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery on your Scaleway account",description:"Learn how to install Qovery on your Scaleway account",permalink:"/guides/installation-guide/guide-scaleway",readingTime:"1 min read",seriesPosition:3,source:"@site/guides/installation-guide/guide-scaleway.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: scaleway",permalink:"/guides/tags/installation-guide-scaleway"}],title:"Install Qovery on your Scaleway account",truncated:!1,prevItem:{title:"Install Qovery your Google Cloud Platform account",permalink:"/guides/installation-guide/guide-google-cloud-platform"},nextItem:{title:"Install Qovery on your Kubernetes cluster",permalink:"/guides/installation-guide/guide-kubernetes"}},u=[],s={rightToc:u};function p(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)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Access our new installation guide of Qovery on Scaleway ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/"}),"here"))))}p.isMDXComponent=!0},449: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):l({},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)}},y=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(n),y=r,d=p["".concat(i,".").concat(y)]||p[y]||f[y]||o;return n?a.a.createElement(d,l({ref:t},u,{components:n})):a.a.createElement(d,l({ref:t},u))}));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]=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: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:a(c,n);u>l;)t[l++]=e;return t}}}]); \ No newline at end of file diff --git a/83a41d86.003a04fd.js.LICENSE.txt b/7cc8f9b8.4e827f65.js.LICENSE.txt similarity index 100% rename from 83a41d86.003a04fd.js.LICENSE.txt rename to 7cc8f9b8.4e827f65.js.LICENSE.txt diff --git a/7df50433.35cc68c8.js b/7df50433.938a988f.js similarity index 96% rename from 7df50433.35cc68c8.js rename to 7df50433.938a988f.js index aee33157db..72455c422c 100644 --- a/7df50433.35cc68c8.js +++ b/7df50433.938a988f.js @@ -1,2 +1,2 @@ -/*! For license information please see 7df50433.35cc68c8.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[137],{288: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(449)),i=n(456),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},447: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 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=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: qovery.env.AWS_ACCESS_KEY\n - name: "AWS_SECRET_ACCESS_KEY"\n value: qovery.env.AWS_SECRET_ACCESS_KEY\n\nfirehose:\n enabled: false\n\nkinesis:\n enabled: false\n\nelasticsearch:\n enabled: false\n')),Object(o.b)("p",null,"You can take a look at additional configuration options on the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://artifacthub.io/packages/helm/aws/aws-for-fluent-bit"}),"AWS provided chart")," "),Object(o.b)("p",null,"Now get to the last step and just ",Object(o.b)("inlineCode",{parentName:"p"},"Create")," the service on Qovery."),Object(o.b)("h3",{id:"store-the-aws-secrets-as-qovery-secrets"},"Store the AWS Secrets as Qovery secrets"),Object(o.b)("p",null,"In the previous step we have assigned the macro ",Object(o.b)("inlineCode",{parentName:"p"},"qovery.env.qovery.env.AWS_ACCESS_KEY")," and ",Object(o.b)("inlineCode",{parentName:"p"},"qovery.env.AWS_SECRET_ACCESS_KEY")," to the AWS secrets. In this step we will create these secrets within the Qovery console."),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Open the service overview of the created Datadog service"),Object(o.b)("li",{parentName:"ul"},"Enter the ",Object(o.b)("inlineCode",{parentName:"li"},"Variables")," section"),Object(o.b)("li",{parentName:"ul"},"Add a new Variable with:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Variable = AWS_SECRET_ACCESS_KEY"),Object(o.b)("li",{parentName:"ul"},"Value = "),Object(o.b)("li",{parentName:"ul"},"Scope = Service (so that it is accessible only to this service)"),Object(o.b)("li",{parentName:"ul"},"Secret variable \u2714\ufe0f"))),Object(o.b)("li",{parentName:"ul"},"Add a new Variable with:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Variable = AWS_ACCESS_KEY"),Object(o.b)("li",{parentName:"ul"},"Value = "),Object(o.b)("li",{parentName:"ul"},"Scope = Service (so that it is accessible only to this service)"),Object(o.b)("li",{parentName:"ul"},"Secret variable \u2714\ufe0f")))),Object(o.b)("p",null,"If you need more information on how to manage your environment variables, have a look at ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"this documentation")),Object(o.b)("h3",{id:"deploy-your-chart"},"Deploy your chart"),Object(o.b)("p",null,"Open the ",Object(o.b)("inlineCode",{parentName:"p"},"Play")," button and trigger the deployment of your chart."),Object(o.b)("h2",{id:"cloudwatch-usage"},"Cloudwatch usage"),Object(o.b)("p",null,"You can now use Cloudwatch to look at your logs. Connect to Cloudwatch, go into the ",Object(o.b)("inlineCode",{parentName:"p"},"Logs insight")," section, then you can perform queries:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/aws-cloudwatch/cloudwatch-search.png",alt:"cloudwatch search"})),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Select the fluent-bit group of logs"),Object(o.b)("li",{parentName:"ol"},"Create a query (",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html"}),"syntax examples"),")"),Object(o.b)("li",{parentName:"ol"},"Run your query"),Object(o.b)("li",{parentName:"ol"},"See the result and expand to filter on other elements")))}b.isMDXComponent=!0},447: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):l({},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,i=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),b=u(n),d=a,m=b["".concat(i,".").concat(d)]||b[d]||p[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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(458),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(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(i.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}))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(454),i=n(447),l=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,s=e.size,u=e.target,b=e.to,p=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 u?r.a.createElement("a",{href:b,target:u,className:p},d):r.a.createElement(o.a,{to:b,className:p},d)}},458: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.bc750b18.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[142],{293: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 b}));var a=n(1),r=n(9),o=(n(0),n(451)),i=(n(459),n(450)),l=(n(455),{last_modified_on:"2024-05-09",$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}),c={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:"5 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:"Import your environment variables with the Qovery CLI",permalink:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli"},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:"Add the AWS EKS helm repository",id:"add-the-aws-eks-helm-repository",children:[]},{value:"Create and deploy the helm chart within Qovery",id:"create-and-deploy-the-helm-chart-within-qovery",children:[]},{value:"Store the AWS Secrets as Qovery secrets",id:"store-the-aws-secrets-as-qovery-secrets",children:[]},{value:"Deploy your chart",id:"deploy-your-chart",children:[]}]},{value:"Cloudwatch usage",id:"cloudwatch-usage",children:[]}],u={rightToc:s};function b(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,"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(o.b)("p",null,"Qovery implementation is based on ",Object(o.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(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Why Qovery does not provides current Loki access?"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"As mentioned Loki is not a full-text search and results may not reflect what you are looking for."),Object(o.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(o.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(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/"}),"Datadog integration"),"."),Object(o.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(o.b)("h2",{id:"aws-permissions-for-cloudwatch"},"AWS permissions for Cloudwatch"),Object(o.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(o.b)("p",null,"On IAM create a policy with the following permissions, and name this policy ",Object(o.b)("inlineCode",{parentName:"p"},"fluent-bit-write-policy"),":"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/aws-cloudwatch/fluent-bit-policy-content.png",alt:"policy content"})),Object(o.b)("pre",null,Object(o.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(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/aws-cloudwatch/fluent-bit-policy-create.png",alt:"policy create"})),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"You can enforce this policy by cluster if you need, by updating the ",Object(o.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(o.b)("p",null,"Once done, let's create a user and attach the policy to it:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/aws-cloudwatch/fluent-bit-user-create.png",alt:"User create"})),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/aws-cloudwatch/fluent-bit-cloudwatch-permissions.png",alt:"User permissions"})),Object(o.b)("p",null,"Finish the user creation and keep credentials for the coming section."),Object(o.b)("h2",{id:"helm"},"Helm"),Object(o.b)("p",null,"We will use ",Object(o.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 and deploy it with Qovery."),Object(o.b)("h3",{id:"add-the-aws-eks-helm-repository"},"Add the AWS EKS helm repository"),Object(o.b)("p",null,"Add the AWS EKS helm repository in your Qovery settings by following ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/helm-repository/"}),"this documentation")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Repository name: ",Object(o.b)("inlineCode",{parentName:"li"},"eks")),Object(o.b)("li",{parentName:"ul"},"Kind: ",Object(o.b)("inlineCode",{parentName:"li"},"HTTPS")),Object(o.b)("li",{parentName:"ul"},"Repository URL: ",Object(o.b)("inlineCode",{parentName:"li"},"https://aws.github.io/eks-charts"))),Object(o.b)("h3",{id:"create-and-deploy-the-helm-chart-within-qovery"},"Create and deploy the helm chart within Qovery"),Object(o.b)("p",null,"Create a helm service in the Qovery environment of your choice (preferrably within a dedicated Tooling project) by following ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/"}),"this documentation")," and these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"General:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Application name: ",Object(o.b)("inlineCode",{parentName:"li"},"fluent-bit")),Object(o.b)("li",{parentName:"ul"},"Source:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Helm source: ",Object(o.b)("inlineCode",{parentName:"li"},"Helm repository")),Object(o.b)("li",{parentName:"ul"},"Repository: ",Object(o.b)("inlineCode",{parentName:"li"},"eks")," (the name given during the AWS EKS helm repository added in the previous step)"),Object(o.b)("li",{parentName:"ul"},"Chart name: ",Object(o.b)("inlineCode",{parentName:"li"},"aws-for-fluent-bit")),Object(o.b)("li",{parentName:"ul"},"Version: ",Object(o.b)("inlineCode",{parentName:"li"},"0.1.21")," (this is the version we used for this setup, update it based on the chosen version)"),Object(o.b)("li",{parentName:"ul"},"Allow cluster-wide resources \u2714\ufe0f"))))),Object(o.b)("li",{parentName:"ul"},"Values",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Values override as file:"),Object(o.b)("li",{parentName:"ul"},"File source: ",Object(o.b)("inlineCode",{parentName:"li"},"Raw YAML")),Object(o.b)("li",{parentName:"ul"},"Raw YAML:")))),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),'priorityClassName: system-node-critical\n\ncloudWatch:\n enabled: true\n region: ""\n logGroupName: "/aws/eks/fluentbit-/logs"\n logRetentionDays: 7\n\nenv:\n - name: "AWS_ACCESS_KEY_ID"\n value: qovery.env.AWS_ACCESS_KEY\n - name: "AWS_SECRET_ACCESS_KEY"\n value: qovery.env.AWS_SECRET_ACCESS_KEY\n\nfirehose:\n enabled: false\n\nkinesis:\n enabled: false\n\nelasticsearch:\n enabled: false\n')),Object(o.b)("p",null,"You can take a look at additional configuration options on the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://artifacthub.io/packages/helm/aws/aws-for-fluent-bit"}),"AWS provided chart")," "),Object(o.b)("p",null,"Now get to the last step and just ",Object(o.b)("inlineCode",{parentName:"p"},"Create")," the service on Qovery."),Object(o.b)("h3",{id:"store-the-aws-secrets-as-qovery-secrets"},"Store the AWS Secrets as Qovery secrets"),Object(o.b)("p",null,"In the previous step we have assigned the macro ",Object(o.b)("inlineCode",{parentName:"p"},"qovery.env.qovery.env.AWS_ACCESS_KEY")," and ",Object(o.b)("inlineCode",{parentName:"p"},"qovery.env.AWS_SECRET_ACCESS_KEY")," to the AWS secrets. In this step we will create these secrets within the Qovery console."),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Open the service overview of the created Datadog service"),Object(o.b)("li",{parentName:"ul"},"Enter the ",Object(o.b)("inlineCode",{parentName:"li"},"Variables")," section"),Object(o.b)("li",{parentName:"ul"},"Add a new Variable with:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Variable = AWS_SECRET_ACCESS_KEY"),Object(o.b)("li",{parentName:"ul"},"Value = "),Object(o.b)("li",{parentName:"ul"},"Scope = Service (so that it is accessible only to this service)"),Object(o.b)("li",{parentName:"ul"},"Secret variable \u2714\ufe0f"))),Object(o.b)("li",{parentName:"ul"},"Add a new Variable with:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Variable = AWS_ACCESS_KEY"),Object(o.b)("li",{parentName:"ul"},"Value = "),Object(o.b)("li",{parentName:"ul"},"Scope = Service (so that it is accessible only to this service)"),Object(o.b)("li",{parentName:"ul"},"Secret variable \u2714\ufe0f")))),Object(o.b)("p",null,"If you need more information on how to manage your environment variables, have a look at ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"this documentation")),Object(o.b)("h3",{id:"deploy-your-chart"},"Deploy your chart"),Object(o.b)("p",null,"Open the ",Object(o.b)("inlineCode",{parentName:"p"},"Play")," button and trigger the deployment of your chart."),Object(o.b)("h2",{id:"cloudwatch-usage"},"Cloudwatch usage"),Object(o.b)("p",null,"You can now use Cloudwatch to look at your logs. Connect to Cloudwatch, go into the ",Object(o.b)("inlineCode",{parentName:"p"},"Logs insight")," section, then you can perform queries:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/aws-cloudwatch/cloudwatch-search.png",alt:"cloudwatch search"})),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Select the fluent-bit group of logs"),Object(o.b)("li",{parentName:"ol"},"Create a query (",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html"}),"syntax examples"),")"),Object(o.b)("li",{parentName:"ol"},"Run your query"),Object(o.b)("li",{parentName:"ol"},"See the result and expand to filter on other elements")))}b.isMDXComponent=!0},449: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):l({},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,i=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),b=u(n),d=a,m=b["".concat(i,".").concat(d)]||b[d]||p[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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(460),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(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(i.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}))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(456),i=n(449),l=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,s=e.size,u=e.target,b=e.to,p=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 u?r.a.createElement("a",{href:b,target:u,className:p},d):r.a.createElement(o.a,{to:b,className:p},d)}},460: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/86a0e6ef.f334a861.js.LICENSE.txt b/83a41d86.bc750b18.js.LICENSE.txt similarity index 100% rename from 86a0e6ef.f334a861.js.LICENSE.txt rename to 83a41d86.bc750b18.js.LICENSE.txt diff --git a/83e9e333.567742cf.js b/83e9e333.3ad8540e.js similarity index 93% rename from 83e9e333.567742cf.js rename to 83e9e333.3ad8540e.js index 39efc708e6..5fb296099f 100644 --- a/83e9e333.567742cf.js +++ b/83e9e333.3ad8540e.js @@ -1,2 +1,2 @@ -/*! For license information please see 83e9e333.567742cf.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[141],{292:function(e,a,t){"use strict";t.r(a);var n=t(0),r=t.n(n),l=t(471),c=(t(293),t(460));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"))))))))}},447: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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),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:A.a.footerLogoLink},r.a.createElement(q,{alt:m.alt,url:u})):r.a.createElement(q,{alt:m.alt,url:u})),r.a.createElement("small",null,c),r.a.createElement("br",null))))},H=t(486),V=t(487),B=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,_=s+Object(y.a)(p),N=Object(y.a)(n),k=Object(B.h)(),w=k?"https://docs.qovery.com"+(k.pathname.endsWith("/")?k.pathname:k.pathname+"/"):null;return r.a.createElement(V.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:N}),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:_}),p&&r.a.createElement("meta",{property:"twitter:image",content:_}),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(L,null),r.a.createElement("div",{className:"main-wrapper"},m),!u&&r.a.createElement(F,null)))}},478: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.3ad8540e.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[143],{294:function(e,a,t){"use strict";t.r(a);var n=t(0),r=t.n(n),l=t(473),c=(t(295),t(462));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"))))))))}},449: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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),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:A.a.footerLogoLink},r.a.createElement(q,{alt:m.alt,url:u})):r.a.createElement(q,{alt:m.alt,url:u})),r.a.createElement("small",null,c),r.a.createElement("br",null))))},H=t(488),V=t(489),B=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,_=s+Object(y.a)(p),N=Object(y.a)(n),k=Object(B.h)(),w=k?"https://docs.qovery.com"+(k.pathname.endsWith("/")?k.pathname:k.pathname+"/"):null;return r.a.createElement(V.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:N}),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:_}),p&&r.a.createElement("meta",{property:"twitter:image",content:_}),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(L,null),r.a.createElement("div",{className:"main-wrapper"},m),!u&&r.a.createElement(F,null)))}},480: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/87080b01.83bdf809.js.LICENSE.txt b/83e9e333.3ad8540e.js.LICENSE.txt similarity index 100% rename from 87080b01.83bdf809.js.LICENSE.txt rename to 83e9e333.3ad8540e.js.LICENSE.txt diff --git a/86a0e6ef.f334a861.js b/86a0e6ef.26b76ec2.js similarity index 89% rename from 86a0e6ef.f334a861.js rename to 86a0e6ef.26b76ec2.js index bd906db807..b13cd17a73 100644 --- a/86a0e6ef.f334a861.js +++ b/86a0e6ef.26b76ec2.js @@ -1,2 +1,2 @@ -/*! For license information please see 86a0e6ef.f334a861.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 l})),r.d(t,"metadata",(function(){return c})),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(449)),i=r(448),l={last_modified_on:"2024-01-26",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Microsoft Azure account",description:"Learn how to install Qovery on your Microsoft Azure account",series_position:5,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: azure"]},c={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery on your Microsoft Azure account",description:"Learn how to install Qovery on your Microsoft Azure account",permalink:"/guides/installation-guide/guide-microsoft-azure",readingTime:"1 min read",seriesPosition:5,source:"@site/guides/installation-guide/guide-microsoft-azure.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: azure",permalink:"/guides/tags/installation-guide-azure"}],title:"Install Qovery on your Microsoft Azure account",truncated:!1,prevItem:{title:"Install Qovery on your Kubernetes cluster",permalink:"/guides/installation-guide/guide-kubernetes"},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=[],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)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Access our new installation guide of Qovery on Azure ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/azure/"}),"here"))))}p.isMDXComponent=!0},447: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):l({},t,{},e)),r},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)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,g=p["".concat(i,".").concat(d)]||p[d]||f[d]||o;return r?a.a.createElement(g,l({ref:t},u,{components:r})):a.a.createElement(g,l({ref:t},u))}));function g(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 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,r),c=i>2?arguments[2]:void 0,u=void 0===c?r:a(c,r);u>l;)t[l++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see 86a0e6ef.26b76ec2.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 l})),r.d(t,"metadata",(function(){return c})),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(451)),i=r(450),l={last_modified_on:"2024-01-26",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Microsoft Azure account",description:"Learn how to install Qovery on your Microsoft Azure account",series_position:5,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: azure"]},c={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery on your Microsoft Azure account",description:"Learn how to install Qovery on your Microsoft Azure account",permalink:"/guides/installation-guide/guide-microsoft-azure",readingTime:"1 min read",seriesPosition:5,source:"@site/guides/installation-guide/guide-microsoft-azure.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: azure",permalink:"/guides/tags/installation-guide-azure"}],title:"Install Qovery on your Microsoft Azure account",truncated:!1,prevItem:{title:"Install Qovery on your Kubernetes cluster",permalink:"/guides/installation-guide/guide-kubernetes"},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=[],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)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Access our new installation guide of Qovery on Azure ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/azure/"}),"here"))))}p.isMDXComponent=!0},449: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):l({},t,{},e)),r},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)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,g=p["".concat(i,".").concat(d)]||p[d]||f[d]||o;return r?a.a.createElement(g,l({ref:t},u,{components:r})):a.a.createElement(g,l({ref:t},u))}));function g(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 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,r),c=i>2?arguments[2]:void 0,u=void 0===c?r:a(c,r);u>l;)t[l++]=e;return t}}}]); \ No newline at end of file diff --git a/888595cd.14a7c940.js.LICENSE.txt b/86a0e6ef.26b76ec2.js.LICENSE.txt similarity index 100% rename from 888595cd.14a7c940.js.LICENSE.txt rename to 86a0e6ef.26b76ec2.js.LICENSE.txt diff --git a/87080b01.83bdf809.js b/87080b01.7e3b0430.js similarity index 89% rename from 87080b01.83bdf809.js rename to 87080b01.7e3b0430.js index bcab2adbb0..478d2821cf 100644 --- a/87080b01.83bdf809.js +++ b/87080b01.7e3b0430.js @@ -1,2 +1,2 @@ -/*! For license information please see 87080b01.83bdf809.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 u})),n.d(t,"default",(function(){return p}));var r=n(1),a=n(9),o=(n(0),n(449)),i=n(457),c={last_modified_on:"2024-05-04",title:"Kubernetes",sidebar_label:"hidden",hide_pagination:!0},s={id:"getting-started/install-qovery/kubernetes",title:"Kubernetes",description:"import Jump from '@site/src/components/Jump';",source:"@site/docs/getting-started/install-qovery/kubernetes.md",permalink:"/docs/getting-started/install-qovery/kubernetes",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Self-Managed Cluster",permalink:"/docs/getting-started/install-qovery/azure/self-managed-cluster"},next:{title:"Quickstart",permalink:"/docs/getting-started/install-qovery/kubernetes/quickstart"}},u=[],l={rightToc:u};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,"Don't be shy, pick the first page you want to read and start your journey with Qovery."),Object(o.b)(i.a,{to:"/docs/getting-started/install-qovery/kubernetes/quickstart",mdxType:"Jump"},"Quickstart"),Object(o.b)(i.a,{to:"/docs/getting-started/install-qovery/kubernetes/byok-config",mdxType:"Jump"},"Configuration"),Object(o.b)(i.a,{to:"/docs/getting-started/install-qovery/kubernetes/validate-installation",mdxType:"Jump"},"Validate Installation"),Object(o.b)(i.a,{to:"/docs/getting-started/install-qovery/kubernetes/faq",mdxType:"Jump"},"FAQ"))}p.isMDXComponent=!0},447: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)},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,u=s(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},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 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;u0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:l})):o.a.createElement("a",Object(r.a)({},e,{href:l}))}},457:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(454),i=n(447),c=n.n(i);n(134);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,f=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-"+(s||"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)}},458: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 87080b01.7e3b0430.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 u})),n.d(t,"default",(function(){return p}));var r=n(1),a=n(9),o=(n(0),n(451)),i=n(459),c={last_modified_on:"2024-05-04",title:"Kubernetes",sidebar_label:"hidden",hide_pagination:!0},s={id:"getting-started/install-qovery/kubernetes",title:"Kubernetes",description:"import Jump from '@site/src/components/Jump';",source:"@site/docs/getting-started/install-qovery/kubernetes.md",permalink:"/docs/getting-started/install-qovery/kubernetes",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Self-Managed Cluster",permalink:"/docs/getting-started/install-qovery/azure/self-managed-cluster"},next:{title:"Quickstart",permalink:"/docs/getting-started/install-qovery/kubernetes/quickstart"}},u=[],l={rightToc:u};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,"Don't be shy, pick the first page you want to read and start your journey with Qovery."),Object(o.b)(i.a,{to:"/docs/getting-started/install-qovery/kubernetes/quickstart",mdxType:"Jump"},"Quickstart"),Object(o.b)(i.a,{to:"/docs/getting-started/install-qovery/kubernetes/byok-config",mdxType:"Jump"},"Configuration"),Object(o.b)(i.a,{to:"/docs/getting-started/install-qovery/kubernetes/validate-installation",mdxType:"Jump"},"Validate Installation"),Object(o.b)(i.a,{to:"/docs/getting-started/install-qovery/kubernetes/faq",mdxType:"Jump"},"FAQ"))}p.isMDXComponent=!0},449: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)},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,u=s(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},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 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;u0)&&(t.unobserve(n),t.disconnect(),r())}))}))).observe(n))},to:l})):o.a.createElement("a",Object(r.a)({},e,{href:l}))}},459:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(456),i=n(449),c=n.n(i);n(134);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,f=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-"+(s||"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)}},460: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/8ae34d0a.e284d087.js.LICENSE.txt b/87080b01.7e3b0430.js.LICENSE.txt similarity index 100% rename from 8ae34d0a.e284d087.js.LICENSE.txt rename to 87080b01.7e3b0430.js.LICENSE.txt diff --git a/888595cd.14a7c940.js b/888595cd.d50148dd.js similarity index 89% rename from 888595cd.14a7c940.js rename to 888595cd.d50148dd.js index 235fd69077..8317d0f1a3 100644 --- a/888595cd.14a7c940.js +++ b/888595cd.d50148dd.js @@ -1,2 +1,2 @@ -/*! For license information please see 888595cd.14a7c940.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 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(449)),i=r(448),c=r(457),l={last_modified_on:"2024-01-03",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 deploying the helm chart with Qovery",id:"by-deploying-the-helm-chart-with-qovery",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-deploying-the-helm-chart-with-qovery"},"By deploying the helm chart with Qovery"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Follow ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/helm/"}),"this guide")," to deploy your Helm Chart with Qovery.")),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},447: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,m=p["".concat(i,".").concat(f)]||p[f]||d[f]||o;return r?a.a.createElement(m,c({ref:t},u,{components:r})):a.a.createElement(m,c({ref:t},u))}));function m(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}},454:function(e,t,r){"use strict";var n=r(1),a=r(0),o=r.n(a),i=r(39),c=r(458),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}))}},457:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(454),i=r(447),c=r.n(i);r(134);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)}},458: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.d50148dd.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[146],{298: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(451)),i=r(450),c=r(459),l={last_modified_on:"2024-01-03",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 deploying the helm chart with Qovery",id:"by-deploying-the-helm-chart-with-qovery",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-deploying-the-helm-chart-with-qovery"},"By deploying the helm chart with Qovery"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Follow ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/helm/"}),"this guide")," to deploy your Helm Chart with Qovery.")),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},449: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,m=p["".concat(i,".").concat(f)]||p[f]||d[f]||o;return r?a.a.createElement(m,c({ref:t},u,{components:r})):a.a.createElement(m,c({ref:t},u))}));function m(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}},456:function(e,t,r){"use strict";var n=r(1),a=r(0),o=r.n(a),i=r(39),c=r(460),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}))}},459:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(456),i=r(449),c=r.n(i);r(134);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)}},460: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/8bfd1931.41a2eccb.js.LICENSE.txt b/888595cd.d50148dd.js.LICENSE.txt similarity index 100% rename from 8bfd1931.41a2eccb.js.LICENSE.txt rename to 888595cd.d50148dd.js.LICENSE.txt diff --git a/89caf623.e3729c28.js b/89caf623.90d2db4b.js similarity index 96% rename from 89caf623.e3729c28.js rename to 89caf623.90d2db4b.js index dfdc77f34f..e172df29c4 100644 --- a/89caf623.e3729c28.js +++ b/89caf623.90d2db4b.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[145],{297: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(449)),i=a(456),s=a(461),o=a(464),c=a(448),b=a(453),u=a(457),p={last_modified_on:"2024-05-03",$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:"13 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://console.qovery.com/"},Object(r.b)("img",{src:"/img/Qovery_Sign_Up_Page.png",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 a headless (without GUI) environment, you can use the following command to sign up and sign in:"),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 Qovery sign-up page will open. Follow the instructions to sign up and sign 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},448:function(e,t,a){"use strict";a(450);var n=a(0),l=a.n(n),r=a(447),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)}},452: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""}}})},453:function(e,t,a){"use strict";a(452);var n=a(0),l=a.n(n),r=a(448);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)}},454:function(e,t,a){"use strict";var n=a(1),l=a(0),r=a.n(l),i=a(39),s=a(458),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}))}},456:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=(a(447),a(455)),i=a.n(r);a(133);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"),"."))}},457:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=a(454),i=a(447),s=a.n(i);a(134);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)}},458:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},461:function(e,t,a){"use strict";var n=a(1),l=(a(465),a(462),a(52),a(29),a(22),a(21),a(0)),r=a.n(l),i=a(469),s=a(447),o=a.n(s),c=a(455),b=a.n(c),u=a(468),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])}},464: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([[147],{299: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(451)),i=a(458),s=a(463),o=a(466),c=a(450),b=a(455),u=a(459),p={last_modified_on:"2024-05-03",$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:"13 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://console.qovery.com/"},Object(r.b)("img",{src:"/img/Qovery_Sign_Up_Page.png",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 a headless (without GUI) environment, you can use the following command to sign up and sign in:"),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 Qovery sign-up page will open. Follow the instructions to sign up and sign 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},450:function(e,t,a){"use strict";a(452);var n=a(0),l=a.n(n),r=a(449),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)}},454: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""}}})},455:function(e,t,a){"use strict";a(454);var n=a(0),l=a.n(n),r=a(450);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)}},456:function(e,t,a){"use strict";var n=a(1),l=a(0),r=a.n(l),i=a(39),s=a(460),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}))}},458:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=(a(449),a(457)),i=a.n(r);a(133);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"),"."))}},459:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=a(456),i=a(449),s=a.n(i);a(134);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)}},460:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},463:function(e,t,a){"use strict";var n=a(1),l=(a(467),a(464),a(52),a(29),a(22),a(21),a(0)),r=a.n(l),i=a(471),s=a(449),o=a.n(s),c=a(457),b=a.n(c),u=a(470),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])}},466: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.a1f7d8fd.js b/89de14d0.f9e3f57c.js similarity index 93% rename from 89de14d0.a1f7d8fd.js rename to 89de14d0.f9e3f57c.js index 96be72a028..cb9973a750 100644 --- a/89de14d0.a1f7d8fd.js +++ b/89de14d0.f9e3f57c.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[146],{298:function(e,r,n){"use strict";n.r(r),n.d(r,"frontMatter",(function(){return a})),n.d(r,"metadata",(function(){return c})),n.d(r,"rightToc",(function(){return u})),n.d(r,"default",(function(){return l}));var t=n(1),o=n(9),i=(n(0),n(449)),a={last_modified_on:"2024-03-28",title:"Provider",description:"Learn how to install Qovery on your provider",sidebar_label:"hidden",hide_pagination:!0},c={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"},u=[],p={rightToc:u};function l(e){var r=e.components,n=Object(o.a)(e,["components"]);return Object(i.b)("wrapper",Object(t.a)({},p,n,{components:r,mdxType:"MDXLayout"}))}l.isMDXComponent=!0},449:function(e,r,n){"use strict";n.d(r,"a",(function(){return f})),n.d(r,"b",(function(){return y}));var t=n(0),o=n.n(t);function i(e,r,n){return r in e?Object.defineProperty(e,r,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[r]=n,e}function a(e,r){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);r&&(t=t.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),n.push.apply(n,t)}return n}function c(e){for(var r=1;r=0||(o[n]=e[n]);return o}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=o.a.createContext({}),l=function(e){var r=o.a.useContext(p),n=r;return e&&(n="function"==typeof e?e(r):c({},r,{},e)),n},f=function(e){var r=l(e.components);return o.a.createElement(p.Provider,{value:r},e.children)},d={inlineCode:"code",wrapper:function(e){var r=e.children;return o.a.createElement(o.a.Fragment,{},r)}},s=Object(t.forwardRef)((function(e,r){var n=e.components,t=e.mdxType,i=e.originalType,a=e.parentName,p=u(e,["components","mdxType","originalType","parentName"]),f=l(n),s=t,y=f["".concat(a,".").concat(s)]||f[s]||d[s]||i;return n?o.a.createElement(y,c({ref:r},p,{components:n})):o.a.createElement(y,c({ref:r},p))}));function y(e,r){var n=arguments,t=r&&r.mdxType;if("string"==typeof e||t){var i=n.length,a=new Array(i);a[0]=s;var c={};for(var u in r)hasOwnProperty.call(r,u)&&(c[u]=r[u]);c.originalType=e,c.mdxType="string"==typeof e?e:t,a[1]=c;for(var p=2;p=0||(o[n]=e[n]);return o}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=o.a.createContext({}),l=function(e){var r=o.a.useContext(p),n=r;return e&&(n="function"==typeof e?e(r):c({},r,{},e)),n},f=function(e){var r=l(e.components);return o.a.createElement(p.Provider,{value:r},e.children)},d={inlineCode:"code",wrapper:function(e){var r=e.children;return o.a.createElement(o.a.Fragment,{},r)}},s=Object(t.forwardRef)((function(e,r){var n=e.components,t=e.mdxType,i=e.originalType,a=e.parentName,p=u(e,["components","mdxType","originalType","parentName"]),f=l(n),s=t,y=f["".concat(a,".").concat(s)]||f[s]||d[s]||i;return n?o.a.createElement(y,c({ref:r},p,{components:n})):o.a.createElement(y,c({ref:r},p))}));function y(e,r){var n=arguments,t=r&&r.mdxType;if("string"==typeof e||t){var i=n.length,a=new Array(i);a[0]=s;var c={};for(var u in r)hasOwnProperty.call(r,u)&&(c[u]=r[u]);c.originalType=e,c.mdxType="string"==typeof e?e:t,a[1]=c;for(var p=2;p kill previous version of instance ","#","1."),Object(r.b)("p",null,"3) Deploy new version of instance ","#","2."),Object(r.b)("p",null,"4) New version of instance ","#","2 is running => kill previous version of instance ","#","2."),Object(r.b)("p",null,"And so on..."),Object(r.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(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deployment-actions/#deploy"}),"deployment section"),". "),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.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(r.b)("h3",{id:"stop"},"Stop"),Object(r.b)("p",null,"The ",Object(r.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(r.b)("inlineCode",{parentName:"p"},"Deployment OK")," or ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment Error"),"."),Object(r.b)("p",null,"The effect on your cluster of the stop operation is different depending on the type of service:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"Application, Container, Container DB ")," : Pods of those services are stopped. Any attached storage is preserved"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"Cloud provider Managed DB"),": the database is paused (only for AWS, not working on Redis)")),Object(r.b)("h3",{id:"restart-service"},"Restart Service"),Object(r.b)("p",null,"The ",Object(r.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(r.b)("inlineCode",{parentName:"p"},"Deployment OK")," and only for a single service."),Object(r.b)("p",null,"Once triggered, the deployment status service goes through the following statuses:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"RESTARTING")," : the request to restart has been received"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"RESTARTED")," : all the pods of the service have been restarted"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"RESTART ERROR")," : Qovery couldn't process the restart request")),Object(r.b)("h3",{id:"cancel-deployment"},"Cancel Deployment"),Object(r.b)("p",null,"The ",Object(r.b)("inlineCode",{parentName:"p"},"Cancel Deployment")," action allows you to abort any ",Object(r.b)("inlineCode",{parentName:"p"},"Deploy")," or ",Object(r.b)("inlineCode",{parentName:"p"},"Redeploy")," action and stop the execution of the deployment pipeline. This action is available only if the current deployment status is ",Object(r.b)("inlineCode",{parentName:"p"},"Queued")," or ",Object(r.b)("inlineCode",{parentName:"p"},"Building")," or ",Object(r.b)("inlineCode",{parentName:"p"},"Deploying"),"."),Object(r.b)("p",null,"If a deployment of a service A is already ongoing, the cancel operation will stop the deployment execution and rollback the service A to the previous version. Any service already deployed during the pipeline execution will not rollback to the previous version."),Object(r.b)("p",null,"For ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/"}),"Lifecycle Jobs"),", the cancel operation is not taken into account unless it is ",Object(r.b)("inlineCode",{parentName:"p"},"forced"),' via the checkbox available in the "Deployment cancel" modal.'),Object(r.b)("h3",{id:"deploy-other-version"},"Deploy other version"),Object(r.b)("p",null,"The ",Object(r.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(r.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(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/deployment/deploy_other_version.png",alt:"Deploy Other Version"})),Object(r.b)("p",null,"By pressing on the Deploy button, a deployment of the service will be triggered using the selected version."),Object(r.b)("h3",{id:"deploy-latest-version"},"Deploy latest version"),Object(r.b)("p",null,"The ",Object(r.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(r.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(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/deployment/deploy_latest_version.png",alt:"Deploy Latest Version"})),Object(r.b)("p",null,"By pressing on the Deploy button, a deployment of the service will be triggered using the selected version."))}u.isMDXComponent=!0},447: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 r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=i.a.createContext({}),p=function(e){var t=i.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 i.a.createElement(c.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,r=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]||r;return n?i.a.createElement(m,l({ref:t},c,{components:n})):i.a.createElement(m,l({ref:t},c))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,a=new Array(r);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:i(s,n);c>l;)t[l++]=e;return t}},452:function(e,t,n){var o=n(28).f,i=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in i||n(10)&&o(i,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},453:function(e,t,n){"use strict";n(452);var o=n(0),i=n.n(o),r=n(448);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)}},454:function(e,t,n){"use strict";var o=n(1),i=n(0),r=n.n(i),a=n(39),l=n(458),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(i.useRef)(!1),d=c.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(p),function(){d&&t&&t.disconnect()}}),[p,d,u]),p&&u?r.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})):r.a.createElement("a",Object(o.a)({},e,{href:p}))}},457:function(e,t,n){"use strict";var o=n(0),i=n.n(o),r=n(454),a=n(447),l=n.n(a);n(134);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=i.a.createElement("div",{className:"jump-to--inner"},i.a.createElement("div",{className:"jump-to--inner-2"},a&&i.a.createElement("div",{className:"jump-to--left"},i.a.createElement("i",{className:"feather icon-"+a})),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-"+(s||"chevron-right")+" arrow"}))));return p?i.a.createElement("a",{href:u,target:p,className:b},d):i.a.createElement(r.a,{to:u,className:b},d)}},458: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.f9775a53.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[149],{301: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),i=n(9),r=(n(0),n(451)),a=(n(459),n(450)),l=(n(455),{last_modified_on:"2024-07-16",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(i.a)(e,["components"]);return Object(r.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(r.b)("p",null,"Qovery allows you to manage the deployment lifecycle of your services and environments via a set of ",Object(r.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(r.b)("p",null,"You can imagine the deployment lifecycle of a service or environment like a state machine: "),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"each state is identified by a ",Object(r.b)("inlineCode",{parentName:"li"},"Deployment Status")),Object(r.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(r.b)("li",{parentName:"ul"},"the list of allowed ",Object(r.b)("inlineCode",{parentName:"li"},"Deployment action")," depends on the current ",Object(r.b)("inlineCode",{parentName:"li"},"Deployment Status"),". Example: if the deployment status is ",Object(r.b)("inlineCode",{parentName:"li"},"Deployment Ok"),", you can trigger only the action ",Object(r.b)("inlineCode",{parentName:"li"},"Stop"),". This will stop the execution of the service (deployment status ",Object(r.b)("inlineCode",{parentName:"li"},"Stopped"),").")),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Example"),":\nWhen a new application is created within Qovery, the application will have the deployment status ",Object(r.b)("inlineCode",{parentName:"p"},"Ready"),". Once the action ",Object(r.b)("inlineCode",{parentName:"p"},"Deploy")," is executed on the service, the service will go through the statuses ",Object(r.b)("inlineCode",{parentName:"p"},"Queued"),", ",Object(r.b)("inlineCode",{parentName:"p"},"Building"),", ",Object(r.b)("inlineCode",{parentName:"p"},"Deploying")," and then finally on the status ",Object(r.b)("inlineCode",{parentName:"p"},"Deployed")," (meaning that the application is correctly deployed). At this point, you can trigger only the action ",Object(r.b)("inlineCode",{parentName:"p"},"Stop")," (This will stop the execution of the service, moving the application to the deployment status ",Object(r.b)("inlineCode",{parentName:"p"},"Stopped"),")."),Object(r.b)("p",null,"You can find the status of the last deployment directly in the Qovery console in the service or environment list:"),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/deployment/deployment_status.png",alt:"Deployment Statuses"})),Object(r.b)("p",null,"Note that the deployment status of the environment is built based on the deployment statuses of each service within it."),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"Deployment Status and Running Status do not provide the same information. Just because a deployment has failed 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(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/running-and-deployment-statuses/"}),"this section")," for more information")),Object(r.b)("p",null,"You can decide to execute a deployment action on:\n1. an environment: via the ",Object(r.b)("inlineCode",{parentName:"p"},"Play")," button at environment level, 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(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deployment-pipeline/"}),"Deployment Pipeline"),"\n2. a single service: via the ",Object(r.b)("inlineCode",{parentName:"p"},"Play")," button at service level, the action will be executed only on the selected service.\n3. a subset of services: selecting one or more services from the service list and using the floating action button. "),Object(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/deployment/deployment_actions.png",alt:"Deployment Actions"})),Object(r.b)("p",null,"Note that all the deployment actions are available via any interface described within ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/interface/"}),"this section"),"."),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"You cannot queue deployment actions 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(r.b)("h2",{id:"deployment-actions"},"Deployment Actions"),Object(r.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(r.b)("h3",{id:"deploy"},"Deploy"),Object(r.b)("p",null,"The ",Object(r.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(r.b)("p",null,"Based on the configuration of your services within, a certain number of ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"https://kubernetes.io/docs/concepts/workloads/pods/"}),"Pods")," will be created in a dedicated ",Object(r.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(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.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(r.b)("p",null,"Once triggered, the deployment of a service goes through the following deployment statuses:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.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(r.b)("li",{parentName:"ul"},Object(r.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(r.b)("strong",{parentName:"li"},"BUILD ERROR")," in case of issues on building your code"),Object(r.b)("li",{parentName:"ul"},Object(r.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(r.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(r.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(r.b)("li",{parentName:"ul"},Object(r.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(r.b)("p",null,"If the deployment was triggered on the entire environment, the environment will go through the following deployment statuses:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"QUEUED")," : at least one service is in status ",Object(r.b)("strong",{parentName:"li"},"QUEUED")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"BUILDING")," : at least one service is in status ",Object(r.b)("strong",{parentName:"li"},"BUILDING")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"DEPLOYING")," : at least one service is in status ",Object(r.b)("strong",{parentName:"li"},"DEPLOYING")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"DEPLOYMENT OK")," : at least one service is in status ",Object(r.b)("strong",{parentName:"li"},"DEPLOYMENT OK")," but none of them is in error (",Object(r.b)("strong",{parentName:"li"},"BUILD ERROR")," or ",Object(r.b)("strong",{parentName:"li"},"DEPLOYMENT ERROR"),")"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"DEPLOYMENT ERROR")," : at least one service is in status ",Object(r.b)("strong",{parentName:"li"},"DEPLOYMENT ERROR"))),Object(r.b)("h3",{id:"redeploy"},"Redeploy"),Object(r.b)("p",null,"The ",Object(r.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(r.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(r.b)("inlineCode",{parentName:"p"},"Deploy")," action has been triggered at least once on the service or environment."),Object(r.b)("p",null,"When replacing the pods of your application, Qovery uses the rolling-restart deployment logic:"),Object(r.b)("p",null,"1) Deploy new version of instance ","#","1."),Object(r.b)("p",null,"2) New version of instance ","#","1 is running => kill previous version of instance ","#","1."),Object(r.b)("p",null,"3) Deploy new version of instance ","#","2."),Object(r.b)("p",null,"4) New version of instance ","#","2 is running => kill previous version of instance ","#","2."),Object(r.b)("p",null,"And so on..."),Object(r.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(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deployment-actions/#deploy"}),"deployment section"),". "),Object(r.b)(a.a,{type:"info",mdxType:"Alert"},Object(r.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(r.b)("h3",{id:"stop"},"Stop"),Object(r.b)("p",null,"The ",Object(r.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(r.b)("inlineCode",{parentName:"p"},"Deployment OK")," or ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment Error"),"."),Object(r.b)("p",null,"The effect on your cluster of the stop operation is different depending on the type of service:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"Application, Container, Container DB ")," : Pods of those services are stopped. Any attached storage is preserved"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"Cloud provider Managed DB"),": the database is paused (only for AWS, not working on Redis)")),Object(r.b)("h3",{id:"restart-service"},"Restart Service"),Object(r.b)("p",null,"The ",Object(r.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(r.b)("inlineCode",{parentName:"p"},"Deployment OK")," and only for a single service."),Object(r.b)("p",null,"Once triggered, the deployment status service goes through the following statuses:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"RESTARTING")," : the request to restart has been received"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"RESTARTED")," : all the pods of the service have been restarted"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("strong",{parentName:"li"},"RESTART ERROR")," : Qovery couldn't process the restart request")),Object(r.b)("h3",{id:"cancel-deployment"},"Cancel Deployment"),Object(r.b)("p",null,"The ",Object(r.b)("inlineCode",{parentName:"p"},"Cancel Deployment")," action allows you to abort any ",Object(r.b)("inlineCode",{parentName:"p"},"Deploy")," or ",Object(r.b)("inlineCode",{parentName:"p"},"Redeploy")," action and stop the execution of the deployment pipeline. This action is available only if the current deployment status is ",Object(r.b)("inlineCode",{parentName:"p"},"Queued")," or ",Object(r.b)("inlineCode",{parentName:"p"},"Building")," or ",Object(r.b)("inlineCode",{parentName:"p"},"Deploying"),"."),Object(r.b)("p",null,"If a deployment of a service A is already ongoing, the cancel operation will stop the deployment execution and rollback the service A to the previous version. Any service already deployed during the pipeline execution will not rollback to the previous version."),Object(r.b)("p",null,"For ",Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/lifecycle-job/"}),"Lifecycle Jobs"),", the cancel operation is not taken into account unless it is ",Object(r.b)("inlineCode",{parentName:"p"},"forced"),' via the checkbox available in the "Deployment cancel" modal.'),Object(r.b)("h3",{id:"deploy-other-version"},"Deploy other version"),Object(r.b)("p",null,"The ",Object(r.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(r.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(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/deployment/deploy_other_version.png",alt:"Deploy Other Version"})),Object(r.b)("p",null,"By pressing on the Deploy button, a deployment of the service will be triggered using the selected version."),Object(r.b)("h3",{id:"deploy-latest-version"},"Deploy latest version"),Object(r.b)("p",null,"The ",Object(r.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(r.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(r.b)("p",{align:"center"},Object(r.b)("img",{src:"/img/deployment/deploy_latest_version.png",alt:"Deploy Latest Version"})),Object(r.b)("p",null,"By pressing on the Deploy button, a deployment of the service will be triggered using the selected version."))}u.isMDXComponent=!0},449: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 r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=i.a.createContext({}),p=function(e){var t=i.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 i.a.createElement(c.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},d=Object(o.forwardRef)((function(e,t){var n=e.components,o=e.mdxType,r=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]||r;return n?i.a.createElement(m,l({ref:t},c,{components:n})):i.a.createElement(m,l({ref:t},c))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,a=new Array(r);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:i(s,n);c>l;)t[l++]=e;return t}},454:function(e,t,n){var o=n(28).f,i=Function.prototype,r=/^\s*function ([^ (]*)/;"name"in i||n(10)&&o(i,"name",{configurable:!0,get:function(){try{return(""+this).match(r)[1]}catch(e){return""}}})},455:function(e,t,n){"use strict";n(454);var o=n(0),i=n.n(o),r=n(450);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)}},456:function(e,t,n){"use strict";var o=n(1),i=n(0),r=n.n(i),a=n(39),l=n(460),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(i.useRef)(!1),d=c.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(p),function(){d&&t&&t.disconnect()}}),[p,d,u]),p&&u?r.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})):r.a.createElement("a",Object(o.a)({},e,{href:p}))}},459:function(e,t,n){"use strict";var o=n(0),i=n.n(o),r=n(456),a=n(449),l=n.n(a);n(134);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=i.a.createElement("div",{className:"jump-to--inner"},i.a.createElement("div",{className:"jump-to--inner-2"},a&&i.a.createElement("div",{className:"jump-to--left"},i.a.createElement("i",{className:"feather icon-"+a})),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-"+(s||"chevron-right")+" arrow"}))));return p?i.a.createElement("a",{href:u,target:p,className:b},d):i.a.createElement(r.a,{to:u,className:b},d)}},460: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.b51b9e03.js.LICENSE.txt b/8ae34d0a.f9775a53.js.LICENSE.txt similarity index 100% rename from 8d146bfd.b51b9e03.js.LICENSE.txt rename to 8ae34d0a.f9775a53.js.LICENSE.txt diff --git a/8bd1b610.35ef06bb.js b/8bd1b610.d21e9aac.js similarity index 95% rename from 8bd1b610.35ef06bb.js rename to 8bd1b610.d21e9aac.js index 78f6f92e86..b14b6b5a94 100644 --- a/8bd1b610.35ef06bb.js +++ b/8bd1b610.d21e9aac.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[148],{300: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(449)),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},449: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||(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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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.6a191cd5.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[151],{303: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(451)),i=(n(458),n(455),n(450),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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.3ef2bc37.js.LICENSE.txt b/8bfd1931.6a191cd5.js.LICENSE.txt similarity index 100% rename from 8d1c77c1.3ef2bc37.js.LICENSE.txt rename to 8bfd1931.6a191cd5.js.LICENSE.txt diff --git a/8ca6d3cf.40ac9d5c.js b/8ca6d3cf.0e7ee7ae.js similarity index 97% rename from 8ca6d3cf.40ac9d5c.js rename to 8ca6d3cf.0e7ee7ae.js index 4637ab9ef2..e08ad5881b 100644 --- a/8ca6d3cf.40ac9d5c.js +++ b/8ca6d3cf.0e7ee7ae.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[150],{302: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(449)),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},449: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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var o=n(0),r=n.n(o),a=n(448);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)}},455:function(e,t,n){"use strict";var o=n(459),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("&"):""}},456:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(447),n(455)),i=n.n(a);n(133);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"),"."))}},459: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.70bce437.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[153],{305: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(451)),i=n(458),c=n(450),l=n(455),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var o=n(0),r=n.n(o),a=n(450);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)}},457:function(e,t,n){"use strict";var o=n(461),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("&"):""}},458:function(e,t,n){"use strict";var o=n(0),r=n.n(o),a=(n(449),n(457)),i=n.n(a);n(133);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"),"."))}},461: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.caaa0bbe.js.LICENSE.txt b/8d146bfd.70bce437.js.LICENSE.txt similarity index 100% rename from 8d5726d6.caaa0bbe.js.LICENSE.txt rename to 8d146bfd.70bce437.js.LICENSE.txt diff --git a/8d1c77c1.3ef2bc37.js b/8d1c77c1.2645ab81.js similarity index 90% rename from 8d1c77c1.3ef2bc37.js rename to 8d1c77c1.2645ab81.js index 93b89cca49..ac1ce70f16 100644 --- a/8d1c77c1.3ef2bc37.js +++ b/8d1c77c1.2645ab81.js @@ -1,2 +1,2 @@ -/*! For license information please see 8d1c77c1.3ef2bc37.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[152],{304: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(449)),a=r(457),c={last_modified_on:"2023-12-20",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},447: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}))}},457:function(e,t,r){"use strict";var n=r(0),o=r.n(n),i=r(454),a=r(447),c=r.n(a);r(134);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)}},458: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 8d1c77c1.2645ab81.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 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(451)),a=r(459),c={last_modified_on:"2023-12-20",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},449: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}))}},459:function(e,t,r){"use strict";var n=r(0),o=r.n(n),i=r(456),a=r(449),c=r.n(a);r(134);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)}},460: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.eae15bfa.js.LICENSE.txt b/8d1c77c1.2645ab81.js.LICENSE.txt similarity index 100% rename from 8f02216a.eae15bfa.js.LICENSE.txt rename to 8d1c77c1.2645ab81.js.LICENSE.txt diff --git a/8d5726d6.caaa0bbe.js b/8d5726d6.86fc53ee.js similarity index 97% rename from 8d5726d6.caaa0bbe.js rename to 8d5726d6.86fc53ee.js index 576d915312..71b7d33980 100644 --- a/8d5726d6.caaa0bbe.js +++ b/8d5726d6.86fc53ee.js @@ -1,2 +1,2 @@ -/*! For license information please see 8d5726d6.caaa0bbe.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[153],{305: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(449)),r=n(456),c=(n(457),n(448)),l=n(453),s={last_modified_on:"2024-07-30",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:"Deployment Restrictions",id:"deployment-restrictions",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:"Advanced Settings",id:"advanced-settings",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). You can add a new git access by clicking on ",Object(i.b)("inlineCode",{parentName:"li"},"New git access"),"."),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. You can add a new container registry by clicking on ",Object(i.b)("inlineCode",{parentName:"li"},"New registry"),"."),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 application (not mandatory)"),Object(i.b)("li",{parentName:"ul"},"CMD Arguments: the arguments to be passed to launch your application (not mandatory) separated with a space. Example: ",Object(i.b)("inlineCode",{parentName:"li"},'rails -h 0.0.0.0 -p 8080 string "complex arg"'),".")),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)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"If the base image in your Dockerfile is from a private registry, you just have to add the access to this registry before creating your application. See ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")," 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)("p",null,Object(i.b)("strong",{parentName:"p"}," Extra labels/annotations (optional)")),Object(i.b)("p",null,"Add your extra annotation/label groups. See the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/labels-annotations/"}),"Add annotation/label group")," section for more information.")),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/roadmap"}),"Suggest us to support it")),Object(i.b)("h4",{id:"option-2-dockerfile"},"Option 2: Dockerfile"),Object(i.b)("p",null,'If your job is built via the Qovery CI (Source="Git Repository"), this section allows you to define the Dockerfile location. '),Object(i.b)("p",null,"If you don't have one, you can use the ",Object(i.b)("inlineCode",{parentName:"p"},"docker init")," command to generate one for your application (check the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.docker.com/reference/cli/docker/init/"}),"documentation here"),"). After creating a Dockerfile, specify the location of your Dockerfile in ",Object(i.b)("inlineCode",{parentName:"p"},"Dockefile path")," field."),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)("h4",{id:"extra-labelsannotations"},"Extra labels/annotations"),Object(i.b)("p",null,"Add your extra annotation/label groups. See the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/labels-annotations/"}),"Add annotation/label group")," section for more information."),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"}),"Connecting 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:"deployment-restrictions"},"Deployment Restrictions"),Object(i.b)("p",null,"This section allows to specify which changes on your repository should trigger an auto-deploy (if enabled). To know more about how to configure your Deployment Restrictions, have a look at the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/#filtering-commits-triggering-the-auto-deploy"}),"deployment restrictions section"),"."),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 and assign a domain to your application (See ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"#qovery-provided-domains"}),"this section")," to know more). You can customize the domain assigned to your application via the ",Object(i.b)("inlineCode",{parentName:"p"},"Domain")," section in the settings (see ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"#custom-domains"}),"this section")," to know more)."),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, you can customize it from the "Domain" section within the application settings.'),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"),"). See ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#qovery-provided-domains"}),"this section")," to know more about these domains.")),Object(i.b)("p",null,"In both cases, you can assign the new custom domain by pressing 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 entry (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 a 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,"After re-deploying the service, 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)(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)("p",null,Object(i.b)("strong",{parentName:"p"}," Special case - domain behind a CDN ")),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 enable the option ",Object(i.b)("inlineCode",{parentName:"p"},"Domain behind a CDN"),' and 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)("p",null,"If you are using Cloudflare to manage your CDN, we can also manage automatically your custom domain configuration via a wildcard domain setup for the whole cluster. Check our ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#use-custom-domain-and-wildcard-tls-for-the-whole-cluster-beta"}),"documentation here")),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-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:"advanced-settings"},"Advanced Settings"),Object(i.b)("p",null,"You can further customize the service behaviour via the service advanced settings. Check ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/advanced-settings/"}),"this documentation")," to know more."),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),o=n.n(a),i=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),o=n(0),i=n.n(o),r=n(39),c=n(458),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}))}},455:function(e,t,n){"use strict";var a=n(459),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("&"):""}},456:function(e,t,n){"use strict";var a=n(0),o=n.n(a),i=(n(447),n(455)),r=n.n(i);n(133);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"),"."))}},457:function(e,t,n){"use strict";var a=n(0),o=n.n(a),i=n(454),r=n(447),c=n.n(r);n(134);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)}},458:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},459: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 8d5726d6.86fc53ee.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[155],{307: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(451)),r=n(458),c=(n(459),n(450)),l=n(455),s={last_modified_on:"2024-07-30",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:"Deployment Restrictions",id:"deployment-restrictions",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:"Advanced Settings",id:"advanced-settings",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). You can add a new git access by clicking on ",Object(i.b)("inlineCode",{parentName:"li"},"New git access"),"."),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. You can add a new container registry by clicking on ",Object(i.b)("inlineCode",{parentName:"li"},"New registry"),"."),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 application (not mandatory)"),Object(i.b)("li",{parentName:"ul"},"CMD Arguments: the arguments to be passed to launch your application (not mandatory) separated with a space. Example: ",Object(i.b)("inlineCode",{parentName:"li"},'rails -h 0.0.0.0 -p 8080 string "complex arg"'),".")),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)(c.a,{type:"info",mdxType:"Alert"},Object(i.b)("p",null,"If the base image in your Dockerfile is from a private registry, you just have to add the access to this registry before creating your application. See ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/container-registry/"}),"Container Registry Management page")," 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)("p",null,Object(i.b)("strong",{parentName:"p"}," Extra labels/annotations (optional)")),Object(i.b)("p",null,"Add your extra annotation/label groups. See the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/labels-annotations/"}),"Add annotation/label group")," section for more information.")),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/roadmap"}),"Suggest us to support it")),Object(i.b)("h4",{id:"option-2-dockerfile"},"Option 2: Dockerfile"),Object(i.b)("p",null,'If your job is built via the Qovery CI (Source="Git Repository"), this section allows you to define the Dockerfile location. '),Object(i.b)("p",null,"If you don't have one, you can use the ",Object(i.b)("inlineCode",{parentName:"p"},"docker init")," command to generate one for your application (check the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.docker.com/reference/cli/docker/init/"}),"documentation here"),"). After creating a Dockerfile, specify the location of your Dockerfile in ",Object(i.b)("inlineCode",{parentName:"p"},"Dockefile path")," field."),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)("h4",{id:"extra-labelsannotations"},"Extra labels/annotations"),Object(i.b)("p",null,"Add your extra annotation/label groups. See the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/labels-annotations/"}),"Add annotation/label group")," section for more information."),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"}),"Connecting 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:"deployment-restrictions"},"Deployment Restrictions"),Object(i.b)("p",null,"This section allows to specify which changes on your repository should trigger an auto-deploy (if enabled). To know more about how to configure your Deployment Restrictions, have a look at the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/#filtering-commits-triggering-the-auto-deploy"}),"deployment restrictions section"),"."),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 and assign a domain to your application (See ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"#qovery-provided-domains"}),"this section")," to know more). You can customize the domain assigned to your application via the ",Object(i.b)("inlineCode",{parentName:"p"},"Domain")," section in the settings (see ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"#custom-domains"}),"this section")," to know more)."),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, you can customize it from the "Domain" section within the application settings.'),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"),"). See ",Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"#qovery-provided-domains"}),"this section")," to know more about these domains.")),Object(i.b)("p",null,"In both cases, you can assign the new custom domain by pressing 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 entry (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 a 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,"After re-deploying the service, 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)(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)("p",null,Object(i.b)("strong",{parentName:"p"}," Special case - domain behind a CDN ")),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 enable the option ",Object(i.b)("inlineCode",{parentName:"p"},"Domain behind a CDN"),' and 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)("p",null,"If you are using Cloudflare to manage your CDN, we can also manage automatically your custom domain configuration via a wildcard domain setup for the whole cluster. Check our ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#use-custom-domain-and-wildcard-tls-for-the-whole-cluster-beta"}),"documentation here")),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-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:"advanced-settings"},"Advanced Settings"),Object(i.b)("p",null,"You can further customize the service behaviour via the service advanced settings. Check ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/advanced-settings/"}),"this documentation")," to know more."),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),o=n.n(a),i=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),o=n(0),i=n.n(o),r=n(39),c=n(460),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}))}},457:function(e,t,n){"use strict";var a=n(461),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("&"):""}},458:function(e,t,n){"use strict";var a=n(0),o=n.n(a),i=(n(449),n(457)),r=n.n(i);n(133);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"),"."))}},459:function(e,t,n){"use strict";var a=n(0),o=n.n(a),i=n(456),r=n(449),c=n.n(r);n(134);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)}},460:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},461: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.adcfaa11.js.LICENSE.txt b/8d5726d6.86fc53ee.js.LICENSE.txt similarity index 100% rename from 9107e302.adcfaa11.js.LICENSE.txt rename to 8d5726d6.86fc53ee.js.LICENSE.txt diff --git a/8f02216a.eae15bfa.js b/8f02216a.04de55bd.js similarity index 89% rename from 8f02216a.eae15bfa.js rename to 8f02216a.04de55bd.js index 8f86be73ee..bb6d1e43c3 100644 --- a/8f02216a.eae15bfa.js +++ b/8f02216a.04de55bd.js @@ -1,2 +1,2 @@ -/*! For license information please see 8f02216a.eae15bfa.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 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(449)),i=(n(456),n(453),n(448),{last_modified_on:"2024-01-10",$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"]}),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:"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"}},l=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",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)("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(r.a)({parentName:"p"},{href:"https://helm.sh"}),"official website"),"."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"You can find ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/"}),"here")," the official documentation on how to deploy a helm chart with Qovery. Below you have two real examples."),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)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Deploy Kubecost"),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost/"}),"How to deploy Kubecost helm chart"))),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Deploy Datadog"),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/"}),"How to deploy Datadog helm chart"))))),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"),"."))}s.isMDXComponent=!0},447: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)}},f=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),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 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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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 8f02216a.04de55bd.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 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(451)),i=(n(458),n(455),n(450),{last_modified_on:"2024-01-10",$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"]}),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:"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"}},l=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",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)("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(r.a)({parentName:"p"},{href:"https://helm.sh"}),"official website"),"."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"You can find ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/"}),"here")," the official documentation on how to deploy a helm chart with Qovery. Below you have two real examples."),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)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Deploy Kubecost"),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost/"}),"How to deploy Kubecost helm chart"))),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Deploy Datadog"),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/"}),"How to deploy Datadog helm chart"))))),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"),"."))}s.isMDXComponent=!0},449: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)}},f=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),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 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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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/91473650.e725ba24.js.LICENSE.txt b/8f02216a.04de55bd.js.LICENSE.txt similarity index 100% rename from 91473650.e725ba24.js.LICENSE.txt rename to 8f02216a.04de55bd.js.LICENSE.txt diff --git a/9107e302.adcfaa11.js b/9107e302.6ec5f90f.js similarity index 92% rename from 9107e302.adcfaa11.js rename to 9107e302.6ec5f90f.js index c6f6358962..bbafb058cb 100644 --- a/9107e302.adcfaa11.js +++ b/9107e302.6ec5f90f.js @@ -1,2 +1,2 @@ -/*! For license information please see 9107e302.adcfaa11.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[155],{307: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(449)),i=n(448),c=(n(453),n(457),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),c=n(458),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}))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(454),i=n(447),c=n.n(i);n(134);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)}},458: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.6ec5f90f.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 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(451)),i=n(450),c=(n(455),n(459),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),c=n(460),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}))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(456),i=n(449),c=n.n(i);n(134);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)}},460: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/91bdc394.15e23c8f.js.LICENSE.txt b/9107e302.6ec5f90f.js.LICENSE.txt similarity index 100% rename from 91bdc394.15e23c8f.js.LICENSE.txt rename to 9107e302.6ec5f90f.js.LICENSE.txt diff --git a/91473650.e725ba24.js b/91473650.76ec0c4e.js similarity index 92% rename from 91473650.e725ba24.js rename to 91473650.76ec0c4e.js index e7b9df1770..405237918a 100644 --- a/91473650.e725ba24.js +++ b/91473650.76ec0c4e.js @@ -1,2 +1,2 @@ -/*! For license information please see 91473650.e725ba24.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 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(449)),a=(n(457),n(448)),c=(n(453),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var i=n(0),o=n.n(i),r=n(448);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)}},454:function(e,t,n){"use strict";var i=n(1),o=n(0),r=n.n(o),a=n(39),c=n(458),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}))}},457:function(e,t,n){"use strict";var i=n(0),o=n.n(i),r=n(454),a=n(447),c=n.n(a);n(134);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)}},458: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.76ec0c4e.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[158],{310: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(451)),a=(n(459),n(450)),c=(n(455),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var i=n(0),o=n.n(i),r=n(450);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)}},456:function(e,t,n){"use strict";var i=n(1),o=n(0),r=n.n(o),a=n(39),c=n(460),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}))}},459:function(e,t,n){"use strict";var i=n(0),o=n.n(i),r=n(456),a=n(449),c=n.n(a);n(134);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)}},460: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/93701b40.a61bdb49.js.LICENSE.txt b/91473650.76ec0c4e.js.LICENSE.txt similarity index 100% rename from 93701b40.a61bdb49.js.LICENSE.txt rename to 91473650.76ec0c4e.js.LICENSE.txt diff --git a/91bdc394.15e23c8f.js b/91bdc394.8d061309.js similarity index 93% rename from 91bdc394.15e23c8f.js rename to 91bdc394.8d061309.js index a802a75bae..91bc127b27 100644 --- a/91bdc394.15e23c8f.js +++ b/91bdc394.8d061309.js @@ -1,2 +1,2 @@ -/*! For license information please see 91bdc394.15e23c8f.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 l})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return b})),n.d(t,"default",(function(){return s}));var a=n(1),r=n(9),o=(n(0),n(449)),i=n(448),l=(n(457),n(453),{last_modified_on:"2024-06-13",title:"Labels & Annotations",description:"Learn how to manage the kubernetes annotations and labels via Qovery"}),c={id:"using-qovery/configuration/organization/labels-annotations",title:"Labels & Annotations",description:"Learn how to manage the kubernetes annotations and labels via Qovery",source:"@site/docs/using-qovery/configuration/organization/labels-annotations.md",permalink:"/docs/using-qovery/configuration/organization/labels-annotations",sidebar:"docs",previous:{title:"API Token",permalink:"/docs/using-qovery/configuration/organization/api-token"},next:{title:"Clusters",permalink:"/docs/using-qovery/configuration/clusters"}},b=[{value:"Create a label group",id:"create-a-label-group",children:[]},{value:"Edit a label group",id:"edit-a-label-group",children:[]},{value:"Delete a label group",id:"delete-a-label-group",children:[]},{value:"Create an annotation group",id:"create-an-annotation-group",children:[]},{value:"Edit an annotation group",id:"edit-an-annotation-group",children:[]},{value:"Delete an annotation group",id:"delete-an-annotation-group",children:[]}],u={rightToc:b};function s(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,"You can manage the extra annotations/labels of the different Kubernetes objects deployed by Qovery directly from the Qovery console."),Object(o.b)("p",null,"In order to have a centralized section to manage the annotations/labels, you can create annotation/label groups in the ",Object(o.b)("inlineCode",{parentName:"p"},"Labels & annotations")," section within the organization settings and then link them to the services."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/organization/annotations_labels_settings.png",alt:"How to access your annotations/labels section"})),Object(o.b)("h2",{id:"create-a-label-group"},"Create a label group"),Object(o.b)("p",null,"You can create a new label group by pressing the ",Object(o.b)("inlineCode",{parentName:"p"},"Add new")," button then ",Object(o.b)("inlineCode",{parentName:"p"},"Add label group"),". You need to provide:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"A group name"),Object(o.b)("li",{parentName:"ul"},"The different label keys/values constituting the group. The key/value have to respect a certain syntax, check the ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set"}),"official Kubernetes documentation")," to learn more.")),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"To ensure that Qovery will be able to continue managing your services. Some labels prefixes are forbidden (this list is not exhaustive):"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"kubernetes.io/")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"k8s.io/")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"envId")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"appId")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"app")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"OwnerId")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"aws")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"cluster_id")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"cluster_long_id")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"organization_id")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"organization_long_id")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery_product")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"creation_date")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Service")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"eks:cluster-name")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"ClusterId")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"ClusterLongId")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"OrganizationId")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"OrganizationLongId")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"eks:nodegroup-name")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"QoveryProduct")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Region")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"creationDate")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"ttl")),Object(o.b)("li",{parentName:"ul"},"all prefixes containing ",Object(o.b)("inlineCode",{parentName:"li"},"qovery.com")))),Object(o.b)("p",null,"A ",Object(o.b)("inlineCode",{parentName:"p"},"Propagate as tag")," is option is available. It allows you to forward the kubernetes label on the resource created by Qovery in your cloud provider."),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"If your Kubernetes label format does not respect the cloud provider tag format. The label will not be propagated to your cloud provider.\nYou can check these documentation to check the tag format depending on your cloud provider:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://docs.aws.amazon.com/tag-editor/latest/userguide/tagging.html#tag-conventions"}),"AWS")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://cloud.google.com/compute/docs/labeling-resources#requirements"}),"GCP")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://www.scaleway.com/en/docs/containers/kubernetes/api-cli/managing-tags/"}),"Scaleway")))),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"For the moment only managed databases on AWS clusters are concerned.\nIn a feature release we will support labels at environment and cluster levels. It will allow you to tag your cloud provider resources (created by Qovery) as a tag such as clusters, S3, VPC, ECR, EC2, ...")),Object(o.b)("p",null,"Example:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/organization/label_group.png",alt:"Label group form"})),Object(o.b)("p",null,"Once validated, the label group will be displayed on the interface."),Object(o.b)("p",null,"You can now apply it your applications, cronjobs, lifecycle jobs and databases."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Helm is not supported as you can directly add extra labels within your helm chart.")),Object(o.b)("h2",{id:"edit-a-label-group"},"Edit a label group"),Object(o.b)("p",null,"You can edit your label group to add/remove/edit labels or update the scope.\nIf this label group was already used in your services. You will have to redeploy them for these changes to be taken into account."),Object(o.b)("h2",{id:"delete-a-label-group"},"Delete a label group"),Object(o.b)("p",null,"You can delete a label group.\nIf this label group was already used in your services. You will have to redeploy them for removing the labels linked to your services."),Object(o.b)("h2",{id:"create-an-annotation-group"},"Create an annotation group"),Object(o.b)("p",null,"As a Qovery service is mapped to multiple Kubernetes objects (pods, deployments, ingress etc..) you will be able to define the kubernetes scope for each annotation group."),Object(o.b)("p",null,"You can create a new annotation group by pressing the ",Object(o.b)("inlineCode",{parentName:"p"},"Add annotation")," button. You need to provide:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"A group name"),Object(o.b)("li",{parentName:"ul"},"The different annotations keys/values constituting the group. The key/value have to respect a certain syntax, check the ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/#syntax-and-character-set"}),"official Kubernetes documentation")," to learn more.")),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"To ensure that Qovery will be able to continue managing your services. Some annotations prefixes are forbidden (this list is not exhaustive):"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"kubernetes.io/")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"k8s.io/")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"appCommitId")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"checksum/config")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"checksum/config-mount-files")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"meta.helm.sh/release-name")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"meta.helm.sh/release-namespace")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"kubernetes.io/")),Object(o.b)("li",{parentName:"ul"},"all prefixes containing ",Object(o.b)("inlineCode",{parentName:"li"},"qovery.com")))),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"A scope: this allows you to define the kubernetes objects where the extra annotations should be applied. Example: If you make your application accessible publicly and add an annotation group with the scope set to ",Object(o.b)("inlineCode",{parentName:"li"},"ingress"),", all annotations within that group will only be added to the ingress of your service.")),Object(o.b)("p",null,"Example:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/organization/annotation_group.png",alt:"Annotation group form"})),Object(o.b)("p",null,"Once validated the annotation group will be displayed on the interface."),Object(o.b)("p",null,"You can now apply it your applications, cronjobs, lifecycle jobs and database containers."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Helm is not supported as you can directly add extra annotations within your helm chart.")),Object(o.b)("h2",{id:"edit-an-annotation-group"},"Edit an annotation group"),Object(o.b)("p",null,"You can edit your annotation group to add/remove/edit annotations or update the scope.\nIf this annotation group was already used in your services. You will have to redeploy them for these changes to be taken into account."),Object(o.b)("h2",{id:"delete-an-annotation-group"},"Delete an annotation group"),Object(o.b)("p",null,"You can delete an annotation group.\nIf this annotation group was already used in your services. You will have to redeploy them for removing the annotations linked to your services."))}s.isMDXComponent=!0},447: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,i=e.parentName,b=c(e,["components","mdxType","originalType","parentName"]),s=u(n),d=a,m=s["".concat(i,".").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,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 b=2;b1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,b=void 0===c?n:r(c,n);b>l;)t[l++]=e;return t}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(458),c=n(20),b=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,u=n||c,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(i.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}))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(454),i=n(447),l=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=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"},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 u?r.a.createElement("a",{href:s,target:u,className:p},d):r.a.createElement(o.a,{to:s,className:p},d)}},458: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 91bdc394.8d061309.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[159],{311: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 b})),n.d(t,"default",(function(){return s}));var a=n(1),r=n(9),o=(n(0),n(451)),i=n(450),l=(n(459),n(455),{last_modified_on:"2024-06-13",title:"Labels & Annotations",description:"Learn how to manage the kubernetes annotations and labels via Qovery"}),c={id:"using-qovery/configuration/organization/labels-annotations",title:"Labels & Annotations",description:"Learn how to manage the kubernetes annotations and labels via Qovery",source:"@site/docs/using-qovery/configuration/organization/labels-annotations.md",permalink:"/docs/using-qovery/configuration/organization/labels-annotations",sidebar:"docs",previous:{title:"API Token",permalink:"/docs/using-qovery/configuration/organization/api-token"},next:{title:"Clusters",permalink:"/docs/using-qovery/configuration/clusters"}},b=[{value:"Create a label group",id:"create-a-label-group",children:[]},{value:"Edit a label group",id:"edit-a-label-group",children:[]},{value:"Delete a label group",id:"delete-a-label-group",children:[]},{value:"Create an annotation group",id:"create-an-annotation-group",children:[]},{value:"Edit an annotation group",id:"edit-an-annotation-group",children:[]},{value:"Delete an annotation group",id:"delete-an-annotation-group",children:[]}],u={rightToc:b};function s(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,"You can manage the extra annotations/labels of the different Kubernetes objects deployed by Qovery directly from the Qovery console."),Object(o.b)("p",null,"In order to have a centralized section to manage the annotations/labels, you can create annotation/label groups in the ",Object(o.b)("inlineCode",{parentName:"p"},"Labels & annotations")," section within the organization settings and then link them to the services."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/organization/annotations_labels_settings.png",alt:"How to access your annotations/labels section"})),Object(o.b)("h2",{id:"create-a-label-group"},"Create a label group"),Object(o.b)("p",null,"You can create a new label group by pressing the ",Object(o.b)("inlineCode",{parentName:"p"},"Add new")," button then ",Object(o.b)("inlineCode",{parentName:"p"},"Add label group"),". You need to provide:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"A group name"),Object(o.b)("li",{parentName:"ul"},"The different label keys/values constituting the group. The key/value have to respect a certain syntax, check the ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set"}),"official Kubernetes documentation")," to learn more.")),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"To ensure that Qovery will be able to continue managing your services. Some labels prefixes are forbidden (this list is not exhaustive):"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"kubernetes.io/")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"k8s.io/")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"envId")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"appId")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"app")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"OwnerId")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"aws")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"cluster_id")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"cluster_long_id")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"organization_id")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"organization_long_id")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery_product")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"creation_date")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Service")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"eks:cluster-name")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"ClusterId")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"ClusterLongId")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"OrganizationId")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"OrganizationLongId")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"eks:nodegroup-name")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"QoveryProduct")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Region")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"creationDate")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"ttl")),Object(o.b)("li",{parentName:"ul"},"all prefixes containing ",Object(o.b)("inlineCode",{parentName:"li"},"qovery.com")))),Object(o.b)("p",null,"A ",Object(o.b)("inlineCode",{parentName:"p"},"Propagate as tag")," is option is available. It allows you to forward the kubernetes label on the resource created by Qovery in your cloud provider."),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"If your Kubernetes label format does not respect the cloud provider tag format. The label will not be propagated to your cloud provider.\nYou can check these documentation to check the tag format depending on your cloud provider:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://docs.aws.amazon.com/tag-editor/latest/userguide/tagging.html#tag-conventions"}),"AWS")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://cloud.google.com/compute/docs/labeling-resources#requirements"}),"GCP")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://www.scaleway.com/en/docs/containers/kubernetes/api-cli/managing-tags/"}),"Scaleway")))),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"For the moment only managed databases on AWS clusters are concerned.\nIn a feature release we will support labels at environment and cluster levels. It will allow you to tag your cloud provider resources (created by Qovery) as a tag such as clusters, S3, VPC, ECR, EC2, ...")),Object(o.b)("p",null,"Example:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/organization/label_group.png",alt:"Label group form"})),Object(o.b)("p",null,"Once validated, the label group will be displayed on the interface."),Object(o.b)("p",null,"You can now apply it your applications, cronjobs, lifecycle jobs and databases."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Helm is not supported as you can directly add extra labels within your helm chart.")),Object(o.b)("h2",{id:"edit-a-label-group"},"Edit a label group"),Object(o.b)("p",null,"You can edit your label group to add/remove/edit labels or update the scope.\nIf this label group was already used in your services. You will have to redeploy them for these changes to be taken into account."),Object(o.b)("h2",{id:"delete-a-label-group"},"Delete a label group"),Object(o.b)("p",null,"You can delete a label group.\nIf this label group was already used in your services. You will have to redeploy them for removing the labels linked to your services."),Object(o.b)("h2",{id:"create-an-annotation-group"},"Create an annotation group"),Object(o.b)("p",null,"As a Qovery service is mapped to multiple Kubernetes objects (pods, deployments, ingress etc..) you will be able to define the kubernetes scope for each annotation group."),Object(o.b)("p",null,"You can create a new annotation group by pressing the ",Object(o.b)("inlineCode",{parentName:"p"},"Add annotation")," button. You need to provide:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"A group name"),Object(o.b)("li",{parentName:"ul"},"The different annotations keys/values constituting the group. The key/value have to respect a certain syntax, check the ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/#syntax-and-character-set"}),"official Kubernetes documentation")," to learn more.")),Object(o.b)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"To ensure that Qovery will be able to continue managing your services. Some annotations prefixes are forbidden (this list is not exhaustive):"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"kubernetes.io/")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"k8s.io/")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"appCommitId")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"checksum/config")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"checksum/config-mount-files")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"meta.helm.sh/release-name")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"meta.helm.sh/release-namespace")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"kubernetes.io/")),Object(o.b)("li",{parentName:"ul"},"all prefixes containing ",Object(o.b)("inlineCode",{parentName:"li"},"qovery.com")))),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"A scope: this allows you to define the kubernetes objects where the extra annotations should be applied. Example: If you make your application accessible publicly and add an annotation group with the scope set to ",Object(o.b)("inlineCode",{parentName:"li"},"ingress"),", all annotations within that group will only be added to the ingress of your service.")),Object(o.b)("p",null,"Example:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/organization/annotation_group.png",alt:"Annotation group form"})),Object(o.b)("p",null,"Once validated the annotation group will be displayed on the interface."),Object(o.b)("p",null,"You can now apply it your applications, cronjobs, lifecycle jobs and database containers."),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Helm is not supported as you can directly add extra annotations within your helm chart.")),Object(o.b)("h2",{id:"edit-an-annotation-group"},"Edit an annotation group"),Object(o.b)("p",null,"You can edit your annotation group to add/remove/edit annotations or update the scope.\nIf this annotation group was already used in your services. You will have to redeploy them for these changes to be taken into account."),Object(o.b)("h2",{id:"delete-an-annotation-group"},"Delete an annotation group"),Object(o.b)("p",null,"You can delete an annotation group.\nIf this annotation group was already used in your services. You will have to redeploy them for removing the annotations linked to your services."))}s.isMDXComponent=!0},449: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,i=e.parentName,b=c(e,["components","mdxType","originalType","parentName"]),s=u(n),d=a,m=s["".concat(i,".").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,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 b=2;b1?arguments[1]:void 0,n),c=i>2?arguments[2]:void 0,b=void 0===c?n:r(c,n);b>l;)t[l++]=e;return t}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(460),c=n(20),b=n.n(c);t.a=function(e){var t,n=e.to,c=e.href,u=n||c,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(i.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}))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(456),i=n(449),l=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=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"},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 u?r.a.createElement("a",{href:s,target:u,className:p},d):r.a.createElement(o.a,{to:s,className:p},d)}},460: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/9406f053.83fd5c12.js.LICENSE.txt b/91bdc394.8d061309.js.LICENSE.txt similarity index 100% rename from 9406f053.83fd5c12.js.LICENSE.txt rename to 91bdc394.8d061309.js.LICENSE.txt diff --git a/93701b40.a61bdb49.js b/93701b40.b6745147.js similarity index 88% rename from 93701b40.a61bdb49.js rename to 93701b40.b6745147.js index fa34a8f167..45085ff882 100644 --- a/93701b40.a61bdb49.js +++ b/93701b40.b6745147.js @@ -1,2 +1,2 @@ -/*! For license information please see 93701b40.a61bdb49.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[158],{310: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(449)),i=(n(456),n(453),n(448)),c={last_modified_on:"2023-12-27",$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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(447),n(455)),i=n.n(a);n(133);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"),"."))}},459: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.b6745147.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 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(451)),i=(n(458),n(455),n(450)),c={last_modified_on:"2023-12-27",$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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(449),n(457)),i=n.n(a);n(133);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"),"."))}},461: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/946bf02d.973635a4.js.LICENSE.txt b/93701b40.b6745147.js.LICENSE.txt similarity index 100% rename from 946bf02d.973635a4.js.LICENSE.txt rename to 93701b40.b6745147.js.LICENSE.txt diff --git a/9406f053.83fd5c12.js b/9406f053.2299f8e3.js similarity index 95% rename from 9406f053.83fd5c12.js rename to 9406f053.2299f8e3.js index d8d572374d..99eba14c30 100644 --- a/9406f053.83fd5c12.js +++ b/9406f053.2299f8e3.js @@ -1,2 +1,2 @@ -/*! For license information please see 9406f053.83fd5c12.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[159],{311: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(449)),a=n(448),c=n(456),l=(n(457),n(453),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var i=n(0),o=n.n(i),r=n(448);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)}},454:function(e,t,n){"use strict";var i=n(1),o=n(0),r=n.n(o),a=n(39),c=n(458),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}))}},455:function(e,t,n){"use strict";var i=n(459),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("&"):""}},456:function(e,t,n){"use strict";var i=n(0),o=n.n(i),r=(n(447),n(455)),a=n.n(r);n(133);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"),"."))}},457:function(e,t,n){"use strict";var i=n(0),o=n.n(i),r=n(454),a=n(447),c=n.n(a);n(134);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)}},458:function(e,t,n){"use strict";function i(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return i}))},459: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.2299f8e3.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[161],{313: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(451)),a=n(450),c=n(458),l=(n(459),n(455),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var i=n(0),o=n.n(i),r=n(450);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)}},456:function(e,t,n){"use strict";var i=n(1),o=n(0),r=n.n(o),a=n(39),c=n(460),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}))}},457:function(e,t,n){"use strict";var i=n(461),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("&"):""}},458:function(e,t,n){"use strict";var i=n(0),o=n.n(i),r=(n(449),n(457)),a=n.n(r);n(133);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"),"."))}},459:function(e,t,n){"use strict";var i=n(0),o=n.n(i),r=n(456),a=n(449),c=n.n(a);n(134);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)}},460:function(e,t,n){"use strict";function i(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return i}))},461: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.0210ef12.js.LICENSE.txt b/9406f053.2299f8e3.js.LICENSE.txt similarity index 100% rename from 94a00d4e.0210ef12.js.LICENSE.txt rename to 9406f053.2299f8e3.js.LICENSE.txt diff --git a/946bf02d.973635a4.js b/946bf02d.7e33f56c.js similarity index 89% rename from 946bf02d.973635a4.js rename to 946bf02d.7e33f56c.js index dc4fc7735c..38a8c736db 100644 --- a/946bf02d.973635a4.js +++ b/946bf02d.7e33f56c.js @@ -1,2 +1,2 @@ -/*! For license information please see 946bf02d.973635a4.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 c})),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(449)),i=n(448),l={last_modified_on:"2024-01-02",$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",series_position:2,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: gcp"]},c={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery your Google Cloud Platform account",description:"Learn how to install Qovery on your Google Cloud Platform (GCP) account",permalink:"/guides/installation-guide/guide-google-cloud-platform",readingTime:"1 min read",seriesPosition:2,source:"@site/guides/installation-guide/guide-google-cloud-platform.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: gcp",permalink:"/guides/tags/installation-guide-gcp"}],title:"Install Qovery your Google Cloud Platform account",truncated:!1,prevItem:{title:"Install Qovery on your Amazon Web Services account",permalink:"/guides/installation-guide/guide-amazon-web-services"},nextItem:{title:"Install Qovery on your Scaleway account",permalink:"/guides/installation-guide/guide-scaleway"}},u=[],s={rightToc:u};function p(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"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Access our new installation guide of Qovery on GCP ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/"}),"here"))))}p.isMDXComponent=!0},447: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)},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,u=c(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,g=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return n?o.a.createElement(g,l({ref:t},u,{components:n})):o.a.createElement(g,l({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 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}}}]); \ No newline at end of file +/*! For license information please see 946bf02d.7e33f56c.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[162],{314: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 p}));var r=n(1),o=n(9),a=(n(0),n(451)),i=n(450),l={last_modified_on:"2024-01-02",$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",series_position:2,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: gcp"]},c={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery your Google Cloud Platform account",description:"Learn how to install Qovery on your Google Cloud Platform (GCP) account",permalink:"/guides/installation-guide/guide-google-cloud-platform",readingTime:"1 min read",seriesPosition:2,source:"@site/guides/installation-guide/guide-google-cloud-platform.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: gcp",permalink:"/guides/tags/installation-guide-gcp"}],title:"Install Qovery your Google Cloud Platform account",truncated:!1,prevItem:{title:"Install Qovery on your Amazon Web Services account",permalink:"/guides/installation-guide/guide-amazon-web-services"},nextItem:{title:"Install Qovery on your Scaleway account",permalink:"/guides/installation-guide/guide-scaleway"}},u=[],s={rightToc:u};function p(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"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Access our new installation guide of Qovery on GCP ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/"}),"here"))))}p.isMDXComponent=!0},449: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)},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,u=c(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,g=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return n?o.a.createElement(g,l({ref:t},u,{components:n})):o.a.createElement(g,l({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 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}}}]); \ No newline at end of file diff --git a/97f5d064.5e196b99.js.LICENSE.txt b/946bf02d.7e33f56c.js.LICENSE.txt similarity index 100% rename from 97f5d064.5e196b99.js.LICENSE.txt rename to 946bf02d.7e33f56c.js.LICENSE.txt diff --git a/94a00d4e.0210ef12.js b/94a00d4e.2e224c8f.js similarity index 95% rename from 94a00d4e.0210ef12.js rename to 94a00d4e.2e224c8f.js index 567a71b6c0..7b61aebefe 100644 --- a/94a00d4e.0210ef12.js +++ b/94a00d4e.2e224c8f.js @@ -1,2 +1,2 @@ -/*! For license information please see 94a00d4e.0210ef12.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 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(449)),o=(t(448),t(453),t(457),{last_modified_on:"2023-12-30",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-aws"}],title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",truncated:!1,prevItem:{title:"Install Qovery on your Microsoft Azure account",permalink:"/guides/installation-guide/guide-microsoft-azure"},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},447: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}},452: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""}}})},453:function(e,n,t){"use strict";t(452);var a=t(0),r=t.n(a),i=t(448);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)}},454:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),l=t(458),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}))}},457:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(454),o=t(447),l=t.n(o);t(134);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)}},458: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.2e224c8f.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[163],{315: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(451)),o=(t(450),t(455),t(459),{last_modified_on:"2023-12-30",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-aws"}],title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",truncated:!1,prevItem:{title:"Install Qovery on your Microsoft Azure account",permalink:"/guides/installation-guide/guide-microsoft-azure"},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},449: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}},454: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""}}})},455:function(e,n,t){"use strict";t(454);var a=t(0),r=t.n(a),i=t(450);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)}},456:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),l=t(460),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}))}},459:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(456),o=t(449),l=t.n(o);t(134);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)}},460: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/9b266254.0fd0af2b.js.LICENSE.txt b/94a00d4e.2e224c8f.js.LICENSE.txt similarity index 100% rename from 9b266254.0fd0af2b.js.LICENSE.txt rename to 94a00d4e.2e224c8f.js.LICENSE.txt diff --git a/952063ba.41813a97.js b/952063ba.0e589e34.js similarity index 96% rename from 952063ba.41813a97.js rename to 952063ba.0e589e34.js index fa68d6c3f9..451797d3ef 100644 --- a/952063ba.41813a97.js +++ b/952063ba.0e589e34.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[162],{314:function(e,a,t){"use strict";t.r(a),t.d(a,"frontMatter",(function(){return i})),t.d(a,"metadata",(function(){return p})),t.d(a,"rightToc",(function(){return d})),t.d(a,"default",(function(){return h}));var n,l=t(1),r=t(9),o=(t(0),t(449)),c=t(464),s=t(456),u=t(448),b=t(461),i={last_modified_on:"2024-07-12",title:"Self-Managed Cluster",description:"Learn how to install and configure Qovery on your Scaleway Kubernetes Service (Kapsule) cluster"},p={id:"getting-started/install-qovery/scaleway/self-managed-cluster",title:"Self-Managed Cluster",description:"Learn how to install and configure Qovery on your Scaleway Kubernetes Service (Kapsule) cluster",source:"@site/docs/getting-started/install-qovery/scaleway/self-managed-cluster.md",permalink:"/docs/getting-started/install-qovery/scaleway/self-managed-cluster",sidebar:"docs",previous:{title:"FAQ",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/faq"},next:{title:"Azure",permalink:"/docs/getting-started/install-qovery/azure"}},d=[{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Install Qovery on your Scaleway Kapsule cluster",id:"install-qovery-on-your-scaleway-kapsule-cluster",children:[]},{value:"What's Next?",id:"whats-next",children:[]}],m=(n="Assumption",function(e){return console.warn("Component "+n+" was not imported, exported, or provided by MDXProvider as global scope"),Object(o.b)("div",e)}),y={rightToc:d};function h(e){var a=e.components,t=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(l.a)({},y,t,{components:a,mdxType:"MDXLayout"}),Object(o.b)(u.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are not familiar with Kubernetes, we recommend you to use Qovery on a Managed Kubernetes cluster on ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/"}),"AWS"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/"}),"GCP"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/"}),"Scaleway"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart/"}),"Azure"),", or contact us.")),Object(o.b)("p",null,"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.\nRead ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/blog/kubernetes-managed-by-qovery-vs-self-managed-byok"}),"this article")," to better understand the difference with the Managed Kubernetes by Qovery. In a nutshell, Qovery 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."),Object(o.b)(u.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery automatically updates ",Object(o.b)("strong",{parentName:"p"},"ONLY")," the Qovery applications (agent, shell-agent etc..) via the Qovery Helm chart. With the self-managed offer it will be up to you to manage any dependency components (ingress, dns, logging...), making sure they run with the right version over time."),Object(o.b)("p",null,"The dependencies provided with the Qovery Helm chart are here to help you with the bootstrap, and are not maintained by Qovery. If you want to simplify the maintenance of your cluster, please look at ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/pricing/"}),"Qovery managed Kubernetes offer"),".")),Object(o.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(o.b)(m,{mdxType:"Assumption"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a Scaleway Kapsule Kubernetes cluster up and running."),Object(o.b)("li",{parentName:"ul"},"You have a Scaleway Kapsule Kubernetes cluster with at least 4 CPUs and 8GB of RAM."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"kubectl")," installed and configured to access your Scaleway Kapsule Kubernetes cluster."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"helm")," installed."),Object(o.b)("li",{parentName:"ul"},"You have a Qovery account. If you don't have one, please sign up at ",Object(o.b)("a",Object(l.a)({parentName:"li"},{href:"https://start.qovery.com"}),"https://start.qovery.com")))),Object(o.b)("h2",{id:"install-qovery-on-your-scaleway-kapsule-cluster"},"Install Qovery on your Scaleway Kapsule cluster"),Object(o.b)(u.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/local/"}),"this guide")," to try Qovery on your local machine.")),Object(o.b)(b.a,{centered:!0,className:"rounded",defaultValue:"automatic",placeholder:"Install Qovery",select:!1,size:null,values:[{group:"Install",label:"Automatic",value:"automatic"},{group:"Install",label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.a,{value:"automatic",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery CLI by running the following command:"),Object(o.b)(b.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)(c.a,{value:"linux",mdxType:"TabItem"},Object(o.b)(b.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.a,{value:"arch",mdxType:"TabItem"},Object(o.b)("p",null,"Qovery is part of ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"macos",mdxType:"TabItem"},Object(o.b)(b.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)(c.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(l.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"windows",mdxType:"TabItem"},Object(o.b)(b.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.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(l.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.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)(c.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(l.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(l.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(l.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)("p",null,"Authenticate with Qovery by running the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(o.b)(u.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are using a headless (without GUI) environment, you can use the following command to sign up and sign in:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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 Qovery sign-up page will open. Follow the instructions to sign up and sign in.")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your Scaleway Kapsule cluster:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"qovery cluster install\n")),Object(o.b)("p",null,"Respond to the prompts to install Qovery on your Scaleway Kapsule Kubernetes cluster."))))),Object(o.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://helm.sh"}),"Helm")," command line tool.")),Object(o.b)("li",null,Object(o.b)("p",null,"Add Qovery Helm repository."),Object(o.b)(u.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery Helm Chart is only available for users who have access to Qovery BYOK. ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/bring-your-own-kubernetes"}),"Request your access here"),".")),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm repo add qovery https://helm.qovery.com\nhelm repo update\n"))),Object(o.b)("li",null,Object(o.b)("p",null,"Login to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console"),", create a cluster of type ",Object(o.b)("inlineCode",{parentName:"p"},"Self-Managed"),". At the end of the flow you will be able to download the ",Object(o.b)("inlineCode",{parentName:"p"},"values.yaml")," file associated with this cluster.")),Object(o.b)("li",null,Object(o.b)("p",null,"Now you can customize your values.yaml file based on your need. Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),"."),Object(o.b)(u.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Make sure that all fields having value ",Object(o.b)("inlineCode",{parentName:"p"},"set-by-customer")," are filled.")),Object(o.b)("p",null,"Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your Kubernetes cluster."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --wait --atomic --create-namespace -n qovery -f \\\n --set services.certificates.cert-manager-configs.enabled=false \\\n --set services.certificates.qovery-cert-manager-webhook.enabled=false \\\n --set services.qovery.qovery-cluster-agent.enabled=false \\\n --set services.qovery.qovery-engine.enabled=false \\\n qovery qovery/qovery\n")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-n qovery"),": the namespace where Qovery and its dependencies will be installed"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"--set..."),": override (only for the first deployment time, if you want to use Cert-Manager) to let cert-manager install its CRDs"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-f your-values-file.yaml"),": the values file you've downloaded, overrided with the Qovery config and your custom config"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery/qovery"),": name of the chart to deploy"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery"),": name of the release")),Object(o.b)("p",null,"If you want to use Cert-Manager, you can remove the ",Object(o.b)("inlineCode",{parentName:"p"},"--set...")," for the future updates (or if already installed):"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --create-namespace -n qovery -f --wait --atomic qovery qovery/qovery\n"))))))),Object(o.b)("p",null,"That's it, you can now use Qovery on your Scaleway Kapsule cluster."),Object(o.b)("p",null,"Connect to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console")," to validate that Qovery is properly installed and start deploying your applications."),Object(o.b)("h2",{id:"whats-next"},"What's Next?"),Object(o.b)("p",null,"Now that you have Qovery installed on your Kubernetes cluster, you can check that Qovery is properly installed by following the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/validate-installation/"}),"Validate Installation")," guide."))}h.isMDXComponent=!0},448:function(e,a,t){"use strict";t(450);var n=t(0),l=t.n(n),r=t(447),o=t.n(r);t(132);a.a=function(e){var a=e.children,t=e.classNames,n=e.fill,r=e.icon,c=e.type,s=null;switch(c){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return l.a.createElement("div",{className:o()(t,"alert","alert--"+c,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&l.a.createElement("i",{className:o()("feather","icon-"+(r||s))}),a)}},456:function(e,a,t){"use strict";var n=t(0),l=t.n(n),r=(t(447),t(455)),o=t.n(r);t(133);a.a=function(e){var a=e.children,t=e.headingDepth,r=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?"+o.a.stringify(s),b=Object(n.useState)(null),i=b[0],p=b[1];return l.a.createElement("div",{className:"steps steps--h"+t},a,!r&&!i&&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:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==i&&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"),"."))}},461:function(e,a,t){"use strict";var n=t(1),l=(t(465),t(462),t(52),t(29),t(22),t(21),t(0)),r=t.n(l),o=t(469),c=t(447),s=t.n(c),u=t(455),b=t.n(u),i=t(468),p=37,d=39;function m(e){var a=e.block,t=e.centered,n=e.changeSelectedValue,l=e.className,o=e.handleKeydown,c=e.style,u=e.values,b=e.selectedValue,i=e.tabRefs;return r.a.createElement("div",{className:t?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:s()("tabs",l,{"tabs--block":a}),style:c},u.map((function(e){var a=e.value,t=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===a,className:s()("tab-item",{"tab-item--active":b===a}),key:a,ref:function(e){return i.push(e)},onKeyDown:function(e){return o(i,e.target,e)},onFocus:function(){return n(a)},onClick:function(){return n(a)}},t)}))))}function y(e){var a=e.placeholder,t=e.selectedValue,n=e.changeSelectedValue,l=e.size,c=e.values,s=c;if(s[0].group){var u=_.groupBy(s,"group");s=Object.keys(u).map((function(e){return{label:e,options:u[e]}}))}return r.a.createElement(o.a,{className:"react-select-container react-select--"+l,classNamePrefix:"react-select",options:s,isClearable:t,placeholder:a,value:c.find((function(e){return e.value==t})),onChange:function(e){return n(e?e.value:null)}})}a.a=function(e){e.block,e.centered;var a=e.children,t=e.defaultValue,o=e.groupId,c=e.label,s=e.placeholder,u=e.select,h=e.size,v=(e.style,e.values),O=e.urlKey,j=Object(i.a)(),g=j.tabGroupChoices,f=j.setTabGroupChoices,w=Object(l.useState)(t),N=w[0],q=w[1];if(null!=o){var T=g[o];null!=T&&T!==N&&q(T)}var k=function(e){q(e),null!=o&&f(o,e)},Q=[],x=function(e,a,t){switch(t.keyCode){case d:!function(e,a){var t=e.indexOf(a)+1;e[t]?e[t].focus():e[0].focus()}(e,a);break;case p:!function(e,a){var t=e.indexOf(a)-1;e[t]?e[t].focus():e[e.length-1].focus()}(e,a)}};return Object(l.useEffect)((function(){if("undefined"!=typeof window&&window.location&&O){var e=b.a.parse(window.location.search);e[O]&&q(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),v.length>1&&(u?r.a.createElement(y,Object(n.a)({changeSelectedValue:k,handleKeydown:x,placeholder:s,selectedValue:N,size:h,tabRefs:Q},e)):r.a.createElement(m,Object(n.a)({changeSelectedValue:k,handleKeydown:x,selectedValue:N,tabRefs:Q},e)))),l.Children.toArray(a).filter((function(e){return e.props.value===N}))[0])}},464:function(e,a,t){"use strict";var n=t(0),l=t.n(n);a.a=function(e){return l.a.createElement(l.a.Fragment,null,e.children)}}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[164],{316:function(e,a,t){"use strict";t.r(a),t.d(a,"frontMatter",(function(){return i})),t.d(a,"metadata",(function(){return p})),t.d(a,"rightToc",(function(){return d})),t.d(a,"default",(function(){return h}));var n,l=t(1),r=t(9),o=(t(0),t(451)),c=t(466),s=t(458),u=t(450),b=t(463),i={last_modified_on:"2024-07-12",title:"Self-Managed Cluster",description:"Learn how to install and configure Qovery on your Scaleway Kubernetes Service (Kapsule) cluster"},p={id:"getting-started/install-qovery/scaleway/self-managed-cluster",title:"Self-Managed Cluster",description:"Learn how to install and configure Qovery on your Scaleway Kubernetes Service (Kapsule) cluster",source:"@site/docs/getting-started/install-qovery/scaleway/self-managed-cluster.md",permalink:"/docs/getting-started/install-qovery/scaleway/self-managed-cluster",sidebar:"docs",previous:{title:"FAQ",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/faq"},next:{title:"Azure",permalink:"/docs/getting-started/install-qovery/azure"}},d=[{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Install Qovery on your Scaleway Kapsule cluster",id:"install-qovery-on-your-scaleway-kapsule-cluster",children:[]},{value:"What's Next?",id:"whats-next",children:[]}],m=(n="Assumption",function(e){return console.warn("Component "+n+" was not imported, exported, or provided by MDXProvider as global scope"),Object(o.b)("div",e)}),y={rightToc:d};function h(e){var a=e.components,t=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(l.a)({},y,t,{components:a,mdxType:"MDXLayout"}),Object(o.b)(u.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are not familiar with Kubernetes, we recommend you to use Qovery on a Managed Kubernetes cluster on ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/"}),"AWS"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/"}),"GCP"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/"}),"Scaleway"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart/"}),"Azure"),", or contact us.")),Object(o.b)("p",null,"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.\nRead ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/blog/kubernetes-managed-by-qovery-vs-self-managed-byok"}),"this article")," to better understand the difference with the Managed Kubernetes by Qovery. In a nutshell, Qovery 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."),Object(o.b)(u.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery automatically updates ",Object(o.b)("strong",{parentName:"p"},"ONLY")," the Qovery applications (agent, shell-agent etc..) via the Qovery Helm chart. With the self-managed offer it will be up to you to manage any dependency components (ingress, dns, logging...), making sure they run with the right version over time."),Object(o.b)("p",null,"The dependencies provided with the Qovery Helm chart are here to help you with the bootstrap, and are not maintained by Qovery. If you want to simplify the maintenance of your cluster, please look at ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/pricing/"}),"Qovery managed Kubernetes offer"),".")),Object(o.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(o.b)(m,{mdxType:"Assumption"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a Scaleway Kapsule Kubernetes cluster up and running."),Object(o.b)("li",{parentName:"ul"},"You have a Scaleway Kapsule Kubernetes cluster with at least 4 CPUs and 8GB of RAM."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"kubectl")," installed and configured to access your Scaleway Kapsule Kubernetes cluster."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"helm")," installed."),Object(o.b)("li",{parentName:"ul"},"You have a Qovery account. If you don't have one, please sign up at ",Object(o.b)("a",Object(l.a)({parentName:"li"},{href:"https://start.qovery.com"}),"https://start.qovery.com")))),Object(o.b)("h2",{id:"install-qovery-on-your-scaleway-kapsule-cluster"},"Install Qovery on your Scaleway Kapsule cluster"),Object(o.b)(u.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/local/"}),"this guide")," to try Qovery on your local machine.")),Object(o.b)(b.a,{centered:!0,className:"rounded",defaultValue:"automatic",placeholder:"Install Qovery",select:!1,size:null,values:[{group:"Install",label:"Automatic",value:"automatic"},{group:"Install",label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.a,{value:"automatic",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery CLI by running the following command:"),Object(o.b)(b.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)(c.a,{value:"linux",mdxType:"TabItem"},Object(o.b)(b.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.a,{value:"arch",mdxType:"TabItem"},Object(o.b)("p",null,"Qovery is part of ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"macos",mdxType:"TabItem"},Object(o.b)(b.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)(c.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(l.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"windows",mdxType:"TabItem"},Object(o.b)(b.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.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(l.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.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)(c.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(l.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(l.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(l.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)("p",null,"Authenticate with Qovery by running the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(o.b)(u.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are using a headless (without GUI) environment, you can use the following command to sign up and sign in:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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 Qovery sign-up page will open. Follow the instructions to sign up and sign in.")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your Scaleway Kapsule cluster:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"qovery cluster install\n")),Object(o.b)("p",null,"Respond to the prompts to install Qovery on your Scaleway Kapsule Kubernetes cluster."))))),Object(o.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://helm.sh"}),"Helm")," command line tool.")),Object(o.b)("li",null,Object(o.b)("p",null,"Add Qovery Helm repository."),Object(o.b)(u.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery Helm Chart is only available for users who have access to Qovery BYOK. ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/bring-your-own-kubernetes"}),"Request your access here"),".")),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm repo add qovery https://helm.qovery.com\nhelm repo update\n"))),Object(o.b)("li",null,Object(o.b)("p",null,"Login to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console"),", create a cluster of type ",Object(o.b)("inlineCode",{parentName:"p"},"Self-Managed"),". At the end of the flow you will be able to download the ",Object(o.b)("inlineCode",{parentName:"p"},"values.yaml")," file associated with this cluster.")),Object(o.b)("li",null,Object(o.b)("p",null,"Now you can customize your values.yaml file based on your need. Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),"."),Object(o.b)(u.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Make sure that all fields having value ",Object(o.b)("inlineCode",{parentName:"p"},"set-by-customer")," are filled.")),Object(o.b)("p",null,"Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your Kubernetes cluster."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --wait --atomic --create-namespace -n qovery -f \\\n --set services.certificates.cert-manager-configs.enabled=false \\\n --set services.certificates.qovery-cert-manager-webhook.enabled=false \\\n --set services.qovery.qovery-cluster-agent.enabled=false \\\n --set services.qovery.qovery-engine.enabled=false \\\n qovery qovery/qovery\n")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-n qovery"),": the namespace where Qovery and its dependencies will be installed"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"--set..."),": override (only for the first deployment time, if you want to use Cert-Manager) to let cert-manager install its CRDs"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-f your-values-file.yaml"),": the values file you've downloaded, overrided with the Qovery config and your custom config"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery/qovery"),": name of the chart to deploy"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery"),": name of the release")),Object(o.b)("p",null,"If you want to use Cert-Manager, you can remove the ",Object(o.b)("inlineCode",{parentName:"p"},"--set...")," for the future updates (or if already installed):"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --create-namespace -n qovery -f --wait --atomic qovery qovery/qovery\n"))))))),Object(o.b)("p",null,"That's it, you can now use Qovery on your Scaleway Kapsule cluster."),Object(o.b)("p",null,"Connect to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console")," to validate that Qovery is properly installed and start deploying your applications."),Object(o.b)("h2",{id:"whats-next"},"What's Next?"),Object(o.b)("p",null,"Now that you have Qovery installed on your Kubernetes cluster, you can check that Qovery is properly installed by following the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/validate-installation/"}),"Validate Installation")," guide."))}h.isMDXComponent=!0},450:function(e,a,t){"use strict";t(452);var n=t(0),l=t.n(n),r=t(449),o=t.n(r);t(132);a.a=function(e){var a=e.children,t=e.classNames,n=e.fill,r=e.icon,c=e.type,s=null;switch(c){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return l.a.createElement("div",{className:o()(t,"alert","alert--"+c,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&l.a.createElement("i",{className:o()("feather","icon-"+(r||s))}),a)}},458:function(e,a,t){"use strict";var n=t(0),l=t.n(n),r=(t(449),t(457)),o=t.n(r);t(133);a.a=function(e){var a=e.children,t=e.headingDepth,r=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?"+o.a.stringify(s),b=Object(n.useState)(null),i=b[0],p=b[1];return l.a.createElement("div",{className:"steps steps--h"+t},a,!r&&!i&&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:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==i&&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"),"."))}},463:function(e,a,t){"use strict";var n=t(1),l=(t(467),t(464),t(52),t(29),t(22),t(21),t(0)),r=t.n(l),o=t(471),c=t(449),s=t.n(c),u=t(457),b=t.n(u),i=t(470),p=37,d=39;function m(e){var a=e.block,t=e.centered,n=e.changeSelectedValue,l=e.className,o=e.handleKeydown,c=e.style,u=e.values,b=e.selectedValue,i=e.tabRefs;return r.a.createElement("div",{className:t?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:s()("tabs",l,{"tabs--block":a}),style:c},u.map((function(e){var a=e.value,t=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":b===a,className:s()("tab-item",{"tab-item--active":b===a}),key:a,ref:function(e){return i.push(e)},onKeyDown:function(e){return o(i,e.target,e)},onFocus:function(){return n(a)},onClick:function(){return n(a)}},t)}))))}function y(e){var a=e.placeholder,t=e.selectedValue,n=e.changeSelectedValue,l=e.size,c=e.values,s=c;if(s[0].group){var u=_.groupBy(s,"group");s=Object.keys(u).map((function(e){return{label:e,options:u[e]}}))}return r.a.createElement(o.a,{className:"react-select-container react-select--"+l,classNamePrefix:"react-select",options:s,isClearable:t,placeholder:a,value:c.find((function(e){return e.value==t})),onChange:function(e){return n(e?e.value:null)}})}a.a=function(e){e.block,e.centered;var a=e.children,t=e.defaultValue,o=e.groupId,c=e.label,s=e.placeholder,u=e.select,h=e.size,v=(e.style,e.values),O=e.urlKey,j=Object(i.a)(),g=j.tabGroupChoices,f=j.setTabGroupChoices,w=Object(l.useState)(t),N=w[0],q=w[1];if(null!=o){var T=g[o];null!=T&&T!==N&&q(T)}var k=function(e){q(e),null!=o&&f(o,e)},Q=[],x=function(e,a,t){switch(t.keyCode){case d:!function(e,a){var t=e.indexOf(a)+1;e[t]?e[t].focus():e[0].focus()}(e,a);break;case p:!function(e,a){var t=e.indexOf(a)-1;e[t]?e[t].focus():e[e.length-1].focus()}(e,a)}};return Object(l.useEffect)((function(){if("undefined"!=typeof window&&window.location&&O){var e=b.a.parse(window.location.search);e[O]&&q(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),v.length>1&&(u?r.a.createElement(y,Object(n.a)({changeSelectedValue:k,handleKeydown:x,placeholder:s,selectedValue:N,size:h,tabRefs:Q},e)):r.a.createElement(m,Object(n.a)({changeSelectedValue:k,handleKeydown:x,selectedValue:N,tabRefs:Q},e)))),l.Children.toArray(a).filter((function(e){return e.props.value===N}))[0])}},466:function(e,a,t){"use strict";var n=t(0),l=t.n(n);a.a=function(e){return l.a.createElement(l.a.Fragment,null,e.children)}}}]); \ No newline at end of file diff --git a/967beaa8.06c0be29.js b/967beaa8.cfc2b881.js similarity index 93% rename from 967beaa8.06c0be29.js rename to 967beaa8.cfc2b881.js index a04bc3fadf..c95e513908 100644 --- a/967beaa8.06c0be29.js +++ b/967beaa8.cfc2b881.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[163],{315: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(449)),l=n(448),i=(n(461),n(453)),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},448:function(e,t,n){"use strict";n(450);var a=n(0),r=n.n(a),o=n(447),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)}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},461:function(e,t,n){"use strict";var a=n(1),r=(n(465),n(462),n(52),n(29),n(22),n(21),n(0)),o=n.n(r),l=n(469),i=n(447),c=n.n(i),u=n(455),s=n.n(u),b=n(468),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([[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 d}));var a=n(1),r=n(9),o=(n(0),n(451)),l=n(450),i=(n(463),n(455)),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},450:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(449),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)}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},463:function(e,t,n){"use strict";var a=n(1),r=(n(467),n(464),n(52),n(29),n(22),n(21),n(0)),o=n.n(r),l=n(471),i=n(449),c=n.n(i),u=n(457),s=n.n(u),b=n(470),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.5e196b99.js b/97f5d064.dd652f6c.js similarity index 89% rename from 97f5d064.5e196b99.js rename to 97f5d064.dd652f6c.js index b72c2b1521..109728bced 100644 --- a/97f5d064.5e196b99.js +++ b/97f5d064.dd652f6c.js @@ -1,2 +1,2 @@ -/*! For license information please see 97f5d064.5e196b99.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[164],{316: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 c})),r.d(t,"default",(function(){return p}));var n=r(1),o=r(9),a=(r(0),r(449)),i=r(448),l={last_modified_on:"2023-12-30",$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","installation_guide: aws"],hide_pagination:!0},u={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:"1 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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"}},c=[],s={rightToc:c};function p(e){var t=e.components,r=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Access our new installation guide of Qovery on AWS ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/"}),"here"))))}p.isMDXComponent=!0},447: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 c=o.a.createContext({}),s=function(e){var t=o.a.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l({},t,{},e)),r},p=function(e){var t=s(e.components);return o.a.createElement(c.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,c=u(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,y=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return r?o.a.createElement(y,l({ref:t},c,{components:r})):o.a.createElement(y,l({ref:t},c))}));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]=d;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l.mdxType="string"==typeof e?e:n,i[1]=l;for(var c=2;c1?arguments[1]:void 0,r),u=i>2?arguments[2]:void 0,c=void 0===u?r:o(u,r);c>l;)t[l++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see 97f5d064.dd652f6c.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[166],{318: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 c})),r.d(t,"default",(function(){return p}));var n=r(1),o=r(9),a=(r(0),r(451)),i=r(450),l={last_modified_on:"2023-12-30",$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","installation_guide: aws"],hide_pagination:!0},u={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:"1 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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"}},c=[],s={rightToc:c};function p(e){var t=e.components,r=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Access our new installation guide of Qovery on AWS ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/"}),"here"))))}p.isMDXComponent=!0},449: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 c=o.a.createContext({}),s=function(e){var t=o.a.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l({},t,{},e)),r},p=function(e){var t=s(e.components);return o.a.createElement(c.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,c=u(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,y=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return r?o.a.createElement(y,l({ref:t},c,{components:r})):o.a.createElement(y,l({ref:t},c))}));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]=d;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l.mdxType="string"==typeof e?e:n,i[1]=l;for(var c=2;c1?arguments[1]:void 0,r),u=i>2?arguments[2]:void 0,c=void 0===u?r:o(u,r);c>l;)t[l++]=e;return t}}}]); \ No newline at end of file diff --git a/9c253a96.b034987e.js.LICENSE.txt b/97f5d064.dd652f6c.js.LICENSE.txt similarity index 100% rename from 9c253a96.b034987e.js.LICENSE.txt rename to 97f5d064.dd652f6c.js.LICENSE.txt diff --git a/9b266254.0fd0af2b.js b/9b266254.bcaeda8e.js similarity index 89% rename from 9b266254.0fd0af2b.js rename to 9b266254.bcaeda8e.js index feb99509e8..f2de376e4d 100644 --- a/9b266254.0fd0af2b.js +++ b/9b266254.bcaeda8e.js @@ -1,2 +1,2 @@ -/*! For license information please see 9b266254.0fd0af2b.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 l})),n.d(t,"metadata",(function(){return c})),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(449)),i=n(448),l={last_modified_on:"2024-01-02",$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",series_position:2,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: gcp"]},c={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery your Google Cloud Platform account",description:"Learn how to install Qovery on your Google Cloud Platform (GCP) account",permalink:"/guides/installation-guide/guide-google-cloud-platform",readingTime:"1 min read",seriesPosition:2,source:"@site/guides/installation-guide/guide-google-cloud-platform.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: gcp",permalink:"/guides/tags/installation-guide-gcp"}],title:"Install Qovery your Google Cloud Platform account",truncated:!1,prevItem:{title:"Install Qovery on your Amazon Web Services account",permalink:"/guides/installation-guide/guide-amazon-web-services"},nextItem:{title:"Install Qovery on your Scaleway account",permalink:"/guides/installation-guide/guide-scaleway"}},u=[],s={rightToc:u};function p(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"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Access our new installation guide of Qovery on GCP ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/"}),"here"))))}p.isMDXComponent=!0},447: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)},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,u=c(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,g=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return n?o.a.createElement(g,l({ref:t},u,{components:n})):o.a.createElement(g,l({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 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}}}]); \ No newline at end of file +/*! For license information please see 9b266254.bcaeda8e.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 l})),n.d(t,"metadata",(function(){return c})),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(451)),i=n(450),l={last_modified_on:"2024-01-02",$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",series_position:2,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: gcp"]},c={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery your Google Cloud Platform account",description:"Learn how to install Qovery on your Google Cloud Platform (GCP) account",permalink:"/guides/installation-guide/guide-google-cloud-platform",readingTime:"1 min read",seriesPosition:2,source:"@site/guides/installation-guide/guide-google-cloud-platform.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: gcp",permalink:"/guides/tags/installation-guide-gcp"}],title:"Install Qovery your Google Cloud Platform account",truncated:!1,prevItem:{title:"Install Qovery on your Amazon Web Services account",permalink:"/guides/installation-guide/guide-amazon-web-services"},nextItem:{title:"Install Qovery on your Scaleway account",permalink:"/guides/installation-guide/guide-scaleway"}},u=[],s={rightToc:u};function p(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"}),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Access our new installation guide of Qovery on GCP ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/"}),"here"))))}p.isMDXComponent=!0},449: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)},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,u=c(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,g=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return n?o.a.createElement(g,l({ref:t},u,{components:n})):o.a.createElement(g,l({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 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}}}]); \ No newline at end of file diff --git a/9c8ed74f.d9b62470.js.LICENSE.txt b/9b266254.bcaeda8e.js.LICENSE.txt similarity index 100% rename from 9c8ed74f.d9b62470.js.LICENSE.txt rename to 9b266254.bcaeda8e.js.LICENSE.txt diff --git a/9c253a96.b034987e.js b/9c253a96.305f64d7.js similarity index 89% rename from 9c253a96.b034987e.js rename to 9c253a96.305f64d7.js index 7ef05c7507..642f467624 100644 --- a/9c253a96.b034987e.js +++ b/9c253a96.305f64d7.js @@ -1,2 +1,2 @@ -/*! For license information please see 9c253a96.b034987e.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[166],{318:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return s})),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(449)),c=r(457),i={last_modified_on:"2023-12-30",title:"Scaleway",sidebar_label:"hidden",hide_pagination:!0},s={id:"getting-started/install-qovery/scaleway",title:"Scaleway",description:"import Jump from '@site/src/components/Jump';",source:"@site/docs/getting-started/install-qovery/scaleway.md",permalink:"/docs/getting-started/install-qovery/scaleway",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Self-Managed Cluster",permalink:"/docs/getting-started/install-qovery/gcp/self-managed-cluster"},next:{title:"Managed By Qovery",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery"}},u=[],l={rightToc:u};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,"It's a good choice. Choose your path:"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery",mdxType:"Jump"},"Cluster Managed by Qovery"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/scaleway/self-managed-cluster",mdxType:"Jump"},"Self-Managed Cluster"))}p.isMDXComponent=!0},447: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({}),l=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=l(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)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),d=n,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||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]=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:n,c[1]=i;for(var u=2;u0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):o.a.createElement("a",Object(n.a)({},e,{href:l}))}},457:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(454),c=r(447),i=r.n(c);r(134);t.a=function(e){var t=e.children,r=e.className,n=e.badge,c=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,f=i()("jump-to","jump-to--"+u,r),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"},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 l?a.a.createElement("a",{href:p,target:l,className:f},d):a.a.createElement(o.a,{to:p,className:f},d)}},458: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 9c253a96.305f64d7.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[168],{320:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return s})),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(451)),c=r(459),i={last_modified_on:"2023-12-30",title:"Scaleway",sidebar_label:"hidden",hide_pagination:!0},s={id:"getting-started/install-qovery/scaleway",title:"Scaleway",description:"import Jump from '@site/src/components/Jump';",source:"@site/docs/getting-started/install-qovery/scaleway.md",permalink:"/docs/getting-started/install-qovery/scaleway",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Self-Managed Cluster",permalink:"/docs/getting-started/install-qovery/gcp/self-managed-cluster"},next:{title:"Managed By Qovery",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery"}},u=[],l={rightToc:u};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,"It's a good choice. Choose your path:"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery",mdxType:"Jump"},"Cluster Managed by Qovery"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/scaleway/self-managed-cluster",mdxType:"Jump"},"Self-Managed Cluster"))}p.isMDXComponent=!0},449: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({}),l=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=l(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)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),d=n,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||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]=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:n,c[1]=i;for(var u=2;u0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):o.a.createElement("a",Object(n.a)({},e,{href:l}))}},459:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(456),c=r(449),i=r.n(c);r(134);t.a=function(e){var t=e.children,r=e.className,n=e.badge,c=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,f=i()("jump-to","jump-to--"+u,r),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"},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 l?a.a.createElement("a",{href:p,target:l,className:f},d):a.a.createElement(o.a,{to:p,className:f},d)}},460: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/9d3c5a68.ba42f458.js.LICENSE.txt b/9c253a96.305f64d7.js.LICENSE.txt similarity index 100% rename from 9d3c5a68.ba42f458.js.LICENSE.txt rename to 9c253a96.305f64d7.js.LICENSE.txt diff --git a/9c8ed74f.d9b62470.js b/9c8ed74f.0fd94c40.js similarity index 89% rename from 9c8ed74f.d9b62470.js rename to 9c8ed74f.0fd94c40.js index 4e160dfee4..037730677d 100644 --- a/9c8ed74f.d9b62470.js +++ b/9c8ed74f.0fd94c40.js @@ -1,2 +1,2 @@ -/*! For license information please see 9c8ed74f.d9b62470.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[167],{319: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(449)),i=(r(456),r(453),r(448)),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},447: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}},452: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""}}})},453:function(e,t,r){"use strict";r(452);var n=r(0),a=r.n(n),o=r(448);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)}},455:function(e,t,r){"use strict";var n=r(459),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("&"):""}},456:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(447),r(455)),i=r.n(o);r(133);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"),"."))}},459: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.0fd94c40.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[169],{321: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(451)),i=(r(458),r(455),r(450)),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},449: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}},454: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""}}})},455:function(e,t,r){"use strict";r(454);var n=r(0),a=r.n(n),o=r(450);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)}},457:function(e,t,r){"use strict";var n=r(461),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("&"):""}},458:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(449),r(457)),i=r.n(o);r(133);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"),"."))}},461: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.89378239.js.LICENSE.txt b/9c8ed74f.0fd94c40.js.LICENSE.txt similarity index 100% rename from 9ddfc3dc.89378239.js.LICENSE.txt rename to 9c8ed74f.0fd94c40.js.LICENSE.txt diff --git a/9d099993.084b2461.js b/9d099993.92d9690d.js similarity index 96% rename from 9d099993.084b2461.js rename to 9d099993.92d9690d.js index a96b783762..00fa820816 100644 --- a/9d099993.084b2461.js +++ b/9d099993.92d9690d.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[168],{320:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),a.d(t,"metadata",(function(){return p})),a.d(t,"rightToc",(function(){return d})),a.d(t,"default",(function(){return h}));var n,l=a(1),r=a(9),o=(a(0),a(449)),c=a(464),s=a(456),b=a(448),u=a(461),i={last_modified_on:"2024-07-12",title:"Quickstart",description:"Learn how to install and configure Qovery on your own Kubernetes cluster (BYOK) / Self-managed Kubernetes cluster"},p={id:"getting-started/install-qovery/kubernetes/quickstart",title:"Quickstart",description:"Learn how to install and configure Qovery on your own Kubernetes cluster (BYOK) / Self-managed Kubernetes cluster",source:"@site/docs/getting-started/install-qovery/kubernetes/quickstart.md",permalink:"/docs/getting-started/install-qovery/kubernetes/quickstart",sidebar:"docs",previous:{title:"Kubernetes",permalink:"/docs/getting-started/install-qovery/kubernetes"},next:{title:"Configuration",permalink:"/docs/getting-started/install-qovery/kubernetes/byok-config"}},d=[{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Install Qovery on your Kubernetes cluster",id:"install-qovery-on-your-kubernetes-cluster",children:[]},{value:"What's Next?",id:"whats-next",children:[]}],m=(n="Assumption",function(e){return console.warn("Component "+n+" was not imported, exported, or provided by MDXProvider as global scope"),Object(o.b)("div",e)}),y={rightToc:d};function h(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(l.a)({},y,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are not familiar with Kubernetes, we recommend you to use Qovery on a Managed Kubernetes cluster on ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/"}),"AWS"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/"}),"GCP"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/"}),"Scaleway"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart/"}),"Azure"),", or contact us.")),Object(o.b)("p",null,"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.\nRead ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/blog/kubernetes-managed-by-qovery-vs-self-managed-byok"}),"this article")," to better understand the difference with the Managed Kubernetes by Qovery. In a nutshell, Qovery 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."),Object(o.b)(b.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery automatically updates ",Object(o.b)("strong",{parentName:"p"},"ONLY")," the Qovery applications (agent, shell-agent etc..) via the Qovery Helm chart. With the self-managed offer it will be up to you to manage any dependency components (ingress, dns, logging...), making sure they run with the right version over time."),Object(o.b)("p",null,"The dependencies provided with the Qovery Helm chart are here to help you with the bootstrap, and are not maintained by Qovery. If you want to simplify the maintenance of your cluster, please look at ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/pricing/"}),"Qovery managed Kubernetes offer"),".")),Object(o.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(o.b)(m,{mdxType:"Assumption"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a Kubernetes Kubernetes cluster up and running."),Object(o.b)("li",{parentName:"ul"},"You have a Kubernetes Kubernetes cluster with at least 4 CPUs and 8GB of RAM."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"kubectl")," installed and configured to access your Kubernetes Kubernetes cluster."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"helm")," installed."),Object(o.b)("li",{parentName:"ul"},"You have a Qovery account. If you don't have one, please sign up at ",Object(o.b)("a",Object(l.a)({parentName:"li"},{href:"https://start.qovery.com"}),"https://start.qovery.com")))),Object(o.b)("h2",{id:"install-qovery-on-your-kubernetes-cluster"},"Install Qovery on your Kubernetes cluster"),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/local/"}),"this guide")," to try Qovery on your local machine.")),Object(o.b)(u.a,{centered:!0,className:"rounded",defaultValue:"automatic",placeholder:"Install Qovery",select:!1,size:null,values:[{group:"Install",label:"Automatic",value:"automatic"},{group:"Install",label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.a,{value:"automatic",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery CLI by running the following command:"),Object(o.b)(u.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)(c.a,{value:"linux",mdxType:"TabItem"},Object(o.b)(u.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.a,{value:"arch",mdxType:"TabItem"},Object(o.b)("p",null,"Qovery is part of ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"macos",mdxType:"TabItem"},Object(o.b)(u.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)(c.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(l.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"windows",mdxType:"TabItem"},Object(o.b)(u.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.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(l.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.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)(c.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(l.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(l.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(l.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)("p",null,"Authenticate with Qovery by running the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are using a headless (without GUI) environment, you can use the following command to sign up and sign in:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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 Qovery sign-up page will open. Follow the instructions to sign up and sign in.")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your Kubernetes cluster:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"qovery cluster install\n")),Object(o.b)("p",null,"Respond to the prompts to install Qovery on your Kubernetes Kubernetes cluster."))))),Object(o.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://helm.sh"}),"Helm")," command line tool.")),Object(o.b)("li",null,Object(o.b)("p",null,"Add Qovery Helm repository."),Object(o.b)(b.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery Helm Chart is only available for users who have access to Qovery BYOK. ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/bring-your-own-kubernetes"}),"Request your access here"),".")),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm repo add qovery https://helm.qovery.com\nhelm repo update\n"))),Object(o.b)("li",null,Object(o.b)("p",null,"Login to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console"),", create a cluster of type ",Object(o.b)("inlineCode",{parentName:"p"},"Self-Managed"),". At the end of the flow you will be able to download the ",Object(o.b)("inlineCode",{parentName:"p"},"values.yaml")," file associated with this cluster.")),Object(o.b)("li",null,Object(o.b)("p",null,"Now you can customize your values.yaml file based on your need. Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),"."),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Make sure that all fields having value ",Object(o.b)("inlineCode",{parentName:"p"},"set-by-customer")," are filled.")),Object(o.b)("p",null,"Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your Kubernetes cluster."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --wait --atomic --create-namespace -n qovery -f \\\n --set services.certificates.cert-manager-configs.enabled=false \\\n --set services.certificates.qovery-cert-manager-webhook.enabled=false \\\n --set services.qovery.qovery-cluster-agent.enabled=false \\\n --set services.qovery.qovery-engine.enabled=false \\\n qovery qovery/qovery\n")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-n qovery"),": the namespace where Qovery and its dependencies will be installed"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"--set..."),": override (only for the first deployment time, if you want to use Cert-Manager) to let cert-manager install its CRDs"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-f your-values-file.yaml"),": the values file you've downloaded, overrided with the Qovery config and your custom config"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery/qovery"),": name of the chart to deploy"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery"),": name of the release")),Object(o.b)("p",null,"If you want to use Cert-Manager, you can remove the ",Object(o.b)("inlineCode",{parentName:"p"},"--set...")," for the future updates (or if already installed):"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --create-namespace -n qovery -f --wait --atomic qovery qovery/qovery\n"))))))),Object(o.b)("p",null,"That's it, you can now use Qovery on your Kubernetes cluster."),Object(o.b)("p",null,"Connect to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console")," to validate that Qovery is properly installed and start deploying your applications."),Object(o.b)("h2",{id:"whats-next"},"What's Next?"),Object(o.b)("p",null,"Now that you have Qovery installed on your Kubernetes cluster, you can check that Qovery is properly installed by following the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/validate-installation/"}),"Validate Installation")," guide."))}h.isMDXComponent=!0},448:function(e,t,a){"use strict";a(450);var n=a(0),l=a.n(n),r=a(447),o=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,s=null;switch(c){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return l.a.createElement("div",{className:o()(a,"alert","alert--"+c,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&l.a.createElement("i",{className:o()("feather","icon-"+(r||s))}),t)}},456:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=(a(447),a(455)),o=a.n(r);a(133);t.a=function(e){var t=e.children,a=e.headingDepth,r=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"},b="https://github.com/qovery/documentation/issues/new?"+o.a.stringify(s),u=Object(n.useState)(null),i=u[0],p=u[1];return l.a.createElement("div",{className:"steps steps--h"+a},t,!r&&!i&&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:b,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==i&&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"),"."))}},461:function(e,t,a){"use strict";var n=a(1),l=(a(465),a(462),a(52),a(29),a(22),a(21),a(0)),r=a.n(l),o=a(469),c=a(447),s=a.n(c),b=a(455),u=a.n(b),i=a(468),p=37,d=39;function m(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,l=e.className,o=e.handleKeydown,c=e.style,b=e.values,u=e.selectedValue,i=e.tabRefs;return r.a.createElement("div",{className:a?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:s()("tabs",l,{"tabs--block":t}),style:c},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:s()("tab-item",{"tab-item--active":u===t}),key:t,ref:function(e){return i.push(e)},onKeyDown:function(e){return o(i,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function y(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,l=e.size,c=e.values,s=c;if(s[0].group){var b=_.groupBy(s,"group");s=Object.keys(b).map((function(e){return{label:e,options:b[e]}}))}return r.a.createElement(o.a,{className:"react-select-container react-select--"+l,classNamePrefix:"react-select",options:s,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,o=e.groupId,c=e.label,s=e.placeholder,b=e.select,h=e.size,v=(e.style,e.values),O=e.urlKey,j=Object(i.a)(),g=j.tabGroupChoices,f=j.setTabGroupChoices,w=Object(l.useState)(a),N=w[0],q=w[1];if(null!=o){var k=g[o];null!=k&&k!==N&&q(k)}var T=function(e){q(e),null!=o&&f(o,e)},Q=[],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=u.a.parse(window.location.search);e[O]&&q(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),v.length>1&&(b?r.a.createElement(y,Object(n.a)({changeSelectedValue:T,handleKeydown:x,placeholder:s,selectedValue:N,size:h,tabRefs:Q},e)):r.a.createElement(m,Object(n.a)({changeSelectedValue:T,handleKeydown:x,selectedValue:N,tabRefs:Q},e)))),l.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},464: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([[170],{322:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),a.d(t,"metadata",(function(){return p})),a.d(t,"rightToc",(function(){return d})),a.d(t,"default",(function(){return h}));var n,l=a(1),r=a(9),o=(a(0),a(451)),c=a(466),s=a(458),b=a(450),u=a(463),i={last_modified_on:"2024-07-12",title:"Quickstart",description:"Learn how to install and configure Qovery on your own Kubernetes cluster (BYOK) / Self-managed Kubernetes cluster"},p={id:"getting-started/install-qovery/kubernetes/quickstart",title:"Quickstart",description:"Learn how to install and configure Qovery on your own Kubernetes cluster (BYOK) / Self-managed Kubernetes cluster",source:"@site/docs/getting-started/install-qovery/kubernetes/quickstart.md",permalink:"/docs/getting-started/install-qovery/kubernetes/quickstart",sidebar:"docs",previous:{title:"Kubernetes",permalink:"/docs/getting-started/install-qovery/kubernetes"},next:{title:"Configuration",permalink:"/docs/getting-started/install-qovery/kubernetes/byok-config"}},d=[{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Install Qovery on your Kubernetes cluster",id:"install-qovery-on-your-kubernetes-cluster",children:[]},{value:"What's Next?",id:"whats-next",children:[]}],m=(n="Assumption",function(e){return console.warn("Component "+n+" was not imported, exported, or provided by MDXProvider as global scope"),Object(o.b)("div",e)}),y={rightToc:d};function h(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(l.a)({},y,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are not familiar with Kubernetes, we recommend you to use Qovery on a Managed Kubernetes cluster on ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/"}),"AWS"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/"}),"GCP"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/"}),"Scaleway"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart/"}),"Azure"),", or contact us.")),Object(o.b)("p",null,"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.\nRead ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/blog/kubernetes-managed-by-qovery-vs-self-managed-byok"}),"this article")," to better understand the difference with the Managed Kubernetes by Qovery. In a nutshell, Qovery 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."),Object(o.b)(b.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery automatically updates ",Object(o.b)("strong",{parentName:"p"},"ONLY")," the Qovery applications (agent, shell-agent etc..) via the Qovery Helm chart. With the self-managed offer it will be up to you to manage any dependency components (ingress, dns, logging...), making sure they run with the right version over time."),Object(o.b)("p",null,"The dependencies provided with the Qovery Helm chart are here to help you with the bootstrap, and are not maintained by Qovery. If you want to simplify the maintenance of your cluster, please look at ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/pricing/"}),"Qovery managed Kubernetes offer"),".")),Object(o.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(o.b)(m,{mdxType:"Assumption"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a Kubernetes Kubernetes cluster up and running."),Object(o.b)("li",{parentName:"ul"},"You have a Kubernetes Kubernetes cluster with at least 4 CPUs and 8GB of RAM."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"kubectl")," installed and configured to access your Kubernetes Kubernetes cluster."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"helm")," installed."),Object(o.b)("li",{parentName:"ul"},"You have a Qovery account. If you don't have one, please sign up at ",Object(o.b)("a",Object(l.a)({parentName:"li"},{href:"https://start.qovery.com"}),"https://start.qovery.com")))),Object(o.b)("h2",{id:"install-qovery-on-your-kubernetes-cluster"},"Install Qovery on your Kubernetes cluster"),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/local/"}),"this guide")," to try Qovery on your local machine.")),Object(o.b)(u.a,{centered:!0,className:"rounded",defaultValue:"automatic",placeholder:"Install Qovery",select:!1,size:null,values:[{group:"Install",label:"Automatic",value:"automatic"},{group:"Install",label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.a,{value:"automatic",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery CLI by running the following command:"),Object(o.b)(u.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)(c.a,{value:"linux",mdxType:"TabItem"},Object(o.b)(u.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.a,{value:"arch",mdxType:"TabItem"},Object(o.b)("p",null,"Qovery is part of ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"macos",mdxType:"TabItem"},Object(o.b)(u.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)(c.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(l.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"windows",mdxType:"TabItem"},Object(o.b)(u.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.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(l.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.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)(c.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(l.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(l.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(l.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)("p",null,"Authenticate with Qovery by running the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are using a headless (without GUI) environment, you can use the following command to sign up and sign in:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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 Qovery sign-up page will open. Follow the instructions to sign up and sign in.")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your Kubernetes cluster:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"qovery cluster install\n")),Object(o.b)("p",null,"Respond to the prompts to install Qovery on your Kubernetes Kubernetes cluster."))))),Object(o.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://helm.sh"}),"Helm")," command line tool.")),Object(o.b)("li",null,Object(o.b)("p",null,"Add Qovery Helm repository."),Object(o.b)(b.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery Helm Chart is only available for users who have access to Qovery BYOK. ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/bring-your-own-kubernetes"}),"Request your access here"),".")),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm repo add qovery https://helm.qovery.com\nhelm repo update\n"))),Object(o.b)("li",null,Object(o.b)("p",null,"Login to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console"),", create a cluster of type ",Object(o.b)("inlineCode",{parentName:"p"},"Self-Managed"),". At the end of the flow you will be able to download the ",Object(o.b)("inlineCode",{parentName:"p"},"values.yaml")," file associated with this cluster.")),Object(o.b)("li",null,Object(o.b)("p",null,"Now you can customize your values.yaml file based on your need. Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),"."),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Make sure that all fields having value ",Object(o.b)("inlineCode",{parentName:"p"},"set-by-customer")," are filled.")),Object(o.b)("p",null,"Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your Kubernetes cluster."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --wait --atomic --create-namespace -n qovery -f \\\n --set services.certificates.cert-manager-configs.enabled=false \\\n --set services.certificates.qovery-cert-manager-webhook.enabled=false \\\n --set services.qovery.qovery-cluster-agent.enabled=false \\\n --set services.qovery.qovery-engine.enabled=false \\\n qovery qovery/qovery\n")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-n qovery"),": the namespace where Qovery and its dependencies will be installed"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"--set..."),": override (only for the first deployment time, if you want to use Cert-Manager) to let cert-manager install its CRDs"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-f your-values-file.yaml"),": the values file you've downloaded, overrided with the Qovery config and your custom config"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery/qovery"),": name of the chart to deploy"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery"),": name of the release")),Object(o.b)("p",null,"If you want to use Cert-Manager, you can remove the ",Object(o.b)("inlineCode",{parentName:"p"},"--set...")," for the future updates (or if already installed):"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --create-namespace -n qovery -f --wait --atomic qovery qovery/qovery\n"))))))),Object(o.b)("p",null,"That's it, you can now use Qovery on your Kubernetes cluster."),Object(o.b)("p",null,"Connect to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console")," to validate that Qovery is properly installed and start deploying your applications."),Object(o.b)("h2",{id:"whats-next"},"What's Next?"),Object(o.b)("p",null,"Now that you have Qovery installed on your Kubernetes cluster, you can check that Qovery is properly installed by following the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/validate-installation/"}),"Validate Installation")," guide."))}h.isMDXComponent=!0},450:function(e,t,a){"use strict";a(452);var n=a(0),l=a.n(n),r=a(449),o=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,s=null;switch(c){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return l.a.createElement("div",{className:o()(a,"alert","alert--"+c,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&l.a.createElement("i",{className:o()("feather","icon-"+(r||s))}),t)}},458:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=(a(449),a(457)),o=a.n(r);a(133);t.a=function(e){var t=e.children,a=e.headingDepth,r=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"},b="https://github.com/qovery/documentation/issues/new?"+o.a.stringify(s),u=Object(n.useState)(null),i=u[0],p=u[1];return l.a.createElement("div",{className:"steps steps--h"+a},t,!r&&!i&&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:b,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==i&&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"),"."))}},463:function(e,t,a){"use strict";var n=a(1),l=(a(467),a(464),a(52),a(29),a(22),a(21),a(0)),r=a.n(l),o=a(471),c=a(449),s=a.n(c),b=a(457),u=a.n(b),i=a(470),p=37,d=39;function m(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,l=e.className,o=e.handleKeydown,c=e.style,b=e.values,u=e.selectedValue,i=e.tabRefs;return r.a.createElement("div",{className:a?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:s()("tabs",l,{"tabs--block":t}),style:c},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:s()("tab-item",{"tab-item--active":u===t}),key:t,ref:function(e){return i.push(e)},onKeyDown:function(e){return o(i,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function y(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,l=e.size,c=e.values,s=c;if(s[0].group){var b=_.groupBy(s,"group");s=Object.keys(b).map((function(e){return{label:e,options:b[e]}}))}return r.a.createElement(o.a,{className:"react-select-container react-select--"+l,classNamePrefix:"react-select",options:s,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,o=e.groupId,c=e.label,s=e.placeholder,b=e.select,h=e.size,v=(e.style,e.values),O=e.urlKey,j=Object(i.a)(),g=j.tabGroupChoices,f=j.setTabGroupChoices,w=Object(l.useState)(a),N=w[0],q=w[1];if(null!=o){var k=g[o];null!=k&&k!==N&&q(k)}var T=function(e){q(e),null!=o&&f(o,e)},Q=[],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=u.a.parse(window.location.search);e[O]&&q(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),v.length>1&&(b?r.a.createElement(y,Object(n.a)({changeSelectedValue:T,handleKeydown:x,placeholder:s,selectedValue:N,size:h,tabRefs:Q},e)):r.a.createElement(m,Object(n.a)({changeSelectedValue:T,handleKeydown:x,selectedValue:N,tabRefs:Q},e)))),l.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},466: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/9d3c5a68.ba42f458.js b/9d3c5a68.ea850d0a.js similarity index 96% rename from 9d3c5a68.ba42f458.js rename to 9d3c5a68.ea850d0a.js index a6e2ab10e5..0086fcc893 100644 --- a/9d3c5a68.ba42f458.js +++ b/9d3c5a68.ea850d0a.js @@ -1,2 +1,2 @@ -/*! For license information please see 9d3c5a68.ba42f458.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 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(449)),c=n(456),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},447: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.d194223d.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 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(451)),i=n(450),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},449: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/9fe26b56.9b748113.js.LICENSE.txt b/9ddfc3dc.d194223d.js.LICENSE.txt similarity index 100% rename from 9fe26b56.9b748113.js.LICENSE.txt rename to 9ddfc3dc.d194223d.js.LICENSE.txt diff --git a/9ecfa6fe.1f070951.js b/9ecfa6fe.2c46d545.js similarity index 87% rename from 9ecfa6fe.1f070951.js rename to 9ecfa6fe.2c46d545.js index c275208cdd..f4435b22f6 100644 --- a/9ecfa6fe.1f070951.js +++ b/9ecfa6fe.2c46d545.js @@ -1,2 +1,2 @@ -/*! For license information please see 9ecfa6fe.1f070951.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[171],{323: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(449)),i=(n(456),n(453),n(448)),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:"Monitor and reduce Kubernetes spend with Kubecost",permalink:"/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost"},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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(447),n(455)),i=n.n(a);n(133);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"),"."))}},459: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.2c46d545.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 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(451)),i=(n(458),n(455),n(450)),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:"Monitor and reduce Kubernetes spend with Kubecost",permalink:"/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost"},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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(449),n(457)),i=n.n(a);n(133);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"),"."))}},461: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/9feef5a0.7f29b0cc.js.LICENSE.txt b/9ecfa6fe.2c46d545.js.LICENSE.txt similarity index 100% rename from 9feef5a0.7f29b0cc.js.LICENSE.txt rename to 9ecfa6fe.2c46d545.js.LICENSE.txt diff --git a/9fe26b56.9b748113.js b/9fe26b56.151308a6.js similarity index 88% rename from 9fe26b56.9b748113.js rename to 9fe26b56.151308a6.js index ba3bbebbb5..dc6fe9d680 100644 --- a/9fe26b56.9b748113.js +++ b/9fe26b56.151308a6.js @@ -1,2 +1,2 @@ -/*! For license information please see 9fe26b56.9b748113.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 l})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return u})),n.d(t,"default",(function(){return p}));var r=n(1),a=n(9),i=(n(0),n(449)),o=n(448),l={last_modified_on:"2024-01-02",$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",series_position:1,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: aws"]},c={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery on your Amazon Web Services account",description:"Learn how to install Qovery on your Amazon Web Services (AWS) account",permalink:"/guides/installation-guide/guide-amazon-web-services",readingTime:"1 min read",seriesPosition:1,source:"@site/guides/installation-guide/guide-amazon-web-services.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: aws",permalink:"/guides/tags/installation-guide-aws"}],title:"Install Qovery on your Amazon Web Services account",truncated:!1,prevItem:{title:"Debugging",permalink:"/guides/getting-started/debugging"},nextItem:{title:"Install Qovery your Google Cloud Platform account",permalink:"/guides/installation-guide/guide-google-cloud-platform"}},u=[],s={rightToc:u};function p(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(i.b)("wrapper",Object(r.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(o.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"Access our new installation guide of Qovery on AWS ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/"}),"here"))))}p.isMDXComponent=!0},447: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 i=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):l({},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)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,o=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,g=p["".concat(o,".").concat(d)]||p[d]||f[d]||i;return n?a.a.createElement(g,l({ref:t},u,{components:n})):a.a.createElement(g,l({ref:t},u))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[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,o[1]=l;for(var u=2;u1?arguments[1]:void 0,n),c=o>2?arguments[2]:void 0,u=void 0===c?n:a(c,n);u>l;)t[l++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see 9fe26b56.151308a6.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[174],{326: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 p}));var r=n(1),a=n(9),i=(n(0),n(451)),o=n(450),l={last_modified_on:"2024-01-02",$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",series_position:1,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: aws"]},c={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery on your Amazon Web Services account",description:"Learn how to install Qovery on your Amazon Web Services (AWS) account",permalink:"/guides/installation-guide/guide-amazon-web-services",readingTime:"1 min read",seriesPosition:1,source:"@site/guides/installation-guide/guide-amazon-web-services.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: aws",permalink:"/guides/tags/installation-guide-aws"}],title:"Install Qovery on your Amazon Web Services account",truncated:!1,prevItem:{title:"Debugging",permalink:"/guides/getting-started/debugging"},nextItem:{title:"Install Qovery your Google Cloud Platform account",permalink:"/guides/installation-guide/guide-google-cloud-platform"}},u=[],s={rightToc:u};function p(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(i.b)("wrapper",Object(r.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)(o.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"Access our new installation guide of Qovery on AWS ",Object(i.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/"}),"here"))))}p.isMDXComponent=!0},449: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 i=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):l({},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)}},d=Object(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,o=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,g=p["".concat(o,".").concat(d)]||p[d]||f[d]||i;return n?a.a.createElement(g,l({ref:t},u,{components:n})):a.a.createElement(g,l({ref:t},u))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[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,o[1]=l;for(var u=2;u1?arguments[1]:void 0,n),c=o>2?arguments[2]:void 0,u=void 0===c?n:a(c,n);u>l;)t[l++]=e;return t}}}]); \ No newline at end of file diff --git a/a156f6a6.d063cbe5.js.LICENSE.txt b/9fe26b56.151308a6.js.LICENSE.txt similarity index 100% rename from a156f6a6.d063cbe5.js.LICENSE.txt rename to 9fe26b56.151308a6.js.LICENSE.txt diff --git a/9feef5a0.7f29b0cc.js b/9feef5a0.70d85061.js similarity index 95% rename from 9feef5a0.7f29b0cc.js rename to 9feef5a0.70d85061.js index 12be4e3775..198307a47c 100644 --- a/9feef5a0.7f29b0cc.js +++ b/9feef5a0.70d85061.js @@ -1,2 +1,2 @@ -/*! For license information please see 9feef5a0.7f29b0cc.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[173],{325: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(449)),i=a(448),c=a(457),l=a(456),s=a(453),b={last_modified_on:"2024-06-13",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)("p",null,Object(o.b)("strong",{parentName:"p"}," Extra labels/annotations (optional)")),Object(o.b)("p",null,"Add your extra annotation/label groups. See the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/labels-annotations/"}),"Add annotation/label group")," section for more information.\nAnnotation groups are not supported for managed databases.")),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)("h4",{id:"extra-labelsannotations"},"Extra labels/annotations"),Object(o.b)("p",null,"Add your extra annotation/label groups. See the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/labels-annotations/"}),"Add annotation/label group")," section for more information.\nAnnotation groups are not supported for managed databases."),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"},""),"_DATABASE_URL"),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"},""),"_DATABASE_URL_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},447: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}},452: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""}}})},453:function(e,t,a){"use strict";a(452);var n=a(0),r=a.n(n),o=a(448);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)}},454:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),i=a(39),c=a(458),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}))}},455:function(e,t,a){"use strict";var n=a(459),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("&"):""}},456:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=(a(447),a(455)),i=a.n(o);a(133);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"),"."))}},457:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(454),i=a(447),c=a.n(i);a(134);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)}},458:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},459: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 9feef5a0.70d85061.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[175],{327: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(451)),i=a(450),c=a(459),l=a(458),s=a(455),b={last_modified_on:"2024-06-13",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)("p",null,Object(o.b)("strong",{parentName:"p"}," Extra labels/annotations (optional)")),Object(o.b)("p",null,"Add your extra annotation/label groups. See the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/labels-annotations/"}),"Add annotation/label group")," section for more information.\nAnnotation groups are not supported for managed databases.")),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)("h4",{id:"extra-labelsannotations"},"Extra labels/annotations"),Object(o.b)("p",null,"Add your extra annotation/label groups. See the ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/labels-annotations/"}),"Add annotation/label group")," section for more information.\nAnnotation groups are not supported for managed databases."),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"},""),"_DATABASE_URL"),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"},""),"_DATABASE_URL_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},449: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}},454: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""}}})},455:function(e,t,a){"use strict";a(454);var n=a(0),r=a.n(n),o=a(450);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)}},456:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),i=a(39),c=a(460),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}))}},457:function(e,t,a){"use strict";var n=a(461),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("&"):""}},458:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=(a(449),a(457)),i=a.n(o);a(133);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"),"."))}},459:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(456),i=a(449),c=a.n(i);a(134);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)}},460:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},461: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.89a09f73.js.LICENSE.txt b/9feef5a0.70d85061.js.LICENSE.txt similarity index 100% rename from a1fea8fb.89a09f73.js.LICENSE.txt rename to 9feef5a0.70d85061.js.LICENSE.txt diff --git a/a156f6a6.d063cbe5.js b/a156f6a6.19bf939a.js similarity index 95% rename from a156f6a6.d063cbe5.js rename to a156f6a6.19bf939a.js index f5ee5e69f2..56a318baf8 100644 --- a/a156f6a6.d063cbe5.js +++ b/a156f6a6.19bf939a.js @@ -1,2 +1,2 @@ -/*! For license information please see a156f6a6.d063cbe5.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[174],{326: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(449)),o=(t(448),t(453),t(457),{last_modified_on:"2023-12-30",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-aws"}],title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",truncated:!1,prevItem:{title:"Install Qovery on your Microsoft Azure account",permalink:"/guides/installation-guide/guide-microsoft-azure"},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},447: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}},452: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""}}})},453:function(e,n,t){"use strict";t(452);var a=t(0),r=t.n(a),i=t(448);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)}},454:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),l=t(458),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}))}},457:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(454),o=t(447),l=t.n(o);t(134);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)}},458: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.19bf939a.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[176],{328: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(451)),o=(t(450),t(455),t(459),{last_modified_on:"2023-12-30",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-aws"}],title:"Blazingly fast Preview Environments for NextJS, NodeJS, and MongoDB on AWS",truncated:!1,prevItem:{title:"Install Qovery on your Microsoft Azure account",permalink:"/guides/installation-guide/guide-microsoft-azure"},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},449: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}},454: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""}}})},455:function(e,n,t){"use strict";t(454);var a=t(0),r=t.n(a),i=t(450);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)}},456:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),l=t(460),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}))}},459:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(456),o=t(449),l=t.n(o);t(134);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)}},460: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.09fe3546.js.LICENSE.txt b/a156f6a6.19bf939a.js.LICENSE.txt similarity index 100% rename from a3cf753a.09fe3546.js.LICENSE.txt rename to a156f6a6.19bf939a.js.LICENSE.txt diff --git a/a1fea8fb.89a09f73.js b/a1fea8fb.ab401d65.js similarity index 91% rename from a1fea8fb.89a09f73.js rename to a1fea8fb.ab401d65.js index 56d72e8f78..8323ef161d 100644 --- a/a1fea8fb.89a09f73.js +++ b/a1fea8fb.ab401d65.js @@ -1,2 +1,2 @@ -/*! For license information please see a1fea8fb.89a09f73.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[175],{327: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(449)),i=(n(448),n(453),n(457),{last_modified_on:"2023-12-30",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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:[]}],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)("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"})))}u.isMDXComponent=!0},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},454:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(458),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),d=Object(a.useRef)(!1),b=s.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(){d.current||(window.docusaurus.preload(u),d.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}))}},457:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(454),i=n(447),c=n.n(i);n(134);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,d=c()("jump-to","jump-to--"+s,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 u?a.a.createElement("a",{href:p,target:u,className:d},b):a.a.createElement(o.a,{to:p,className:d},b)}},458: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.ab401d65.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[177],{329: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(451)),i=(n(450),n(455),n(459),{last_modified_on:"2023-12-30",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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:[]}],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)("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"})))}u.isMDXComponent=!0},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},456:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(460),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),d=Object(a.useRef)(!1),b=s.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(){d.current||(window.docusaurus.preload(u),d.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}))}},459:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(456),i=n(449),c=n.n(i);n(134);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,d=c()("jump-to","jump-to--"+s,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 u?a.a.createElement("a",{href:p,target:u,className:d},b):a.a.createElement(o.a,{to:p,className:d},b)}},460: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.3ce70155.js.LICENSE.txt b/a1fea8fb.ab401d65.js.LICENSE.txt similarity index 100% rename from a4401f0f.3ce70155.js.LICENSE.txt rename to a1fea8fb.ab401d65.js.LICENSE.txt diff --git a/a264e41a.51acd114.js b/a264e41a.9c464d6a.js similarity index 73% rename from a264e41a.51acd114.js rename to a264e41a.9c464d6a.js index 6b9d3770ae..9a0e6b12de 100644 --- a/a264e41a.51acd114.js +++ b/a264e41a.9c464d6a.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[176],{328: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([[178],{330: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.09fe3546.js b/a3cf753a.755b63a0.js similarity index 96% rename from a3cf753a.09fe3546.js rename to a3cf753a.755b63a0.js index f3d9b7a79b..f36b708527 100644 --- a/a3cf753a.09fe3546.js +++ b/a3cf753a.755b63a0.js @@ -1,2 +1,2 @@ -/*! For license information please see a3cf753a.09fe3546.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[177],{329: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(449)),o=t(456),l=t(448),c=t(453),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 JupyterHub using Helm",permalink:"/guides/tutorial/deploy-jupyterhub-qovery"},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},447: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}},452: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""}}})},453:function(e,n,t){"use strict";t(452);var i=t(0),r=t.n(i),a=t(448);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)}},455:function(e,n,t){"use strict";var i=t(459),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("&"):""}},456:function(e,n,t){"use strict";var i=t(0),r=t.n(i),a=(t(447),t(455)),o=t.n(a);t(133);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"),"."))}},459: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.755b63a0.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[179],{331: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(451)),o=t(458),l=t(450),c=t(455),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 JupyterHub using Helm",permalink:"/guides/tutorial/deploy-jupyterhub-qovery"},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},449: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}},454: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""}}})},455:function(e,n,t){"use strict";t(454);var i=t(0),r=t.n(i),a=t(450);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)}},457:function(e,n,t){"use strict";var i=t(461),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("&"):""}},458:function(e,n,t){"use strict";var i=t(0),r=t.n(i),a=(t(449),t(457)),o=t.n(a);t(133);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"),"."))}},461: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.696ee9c1.js.LICENSE.txt b/a3cf753a.755b63a0.js.LICENSE.txt similarity index 100% rename from a4459aa8.696ee9c1.js.LICENSE.txt rename to a3cf753a.755b63a0.js.LICENSE.txt diff --git a/a4401f0f.3ce70155.js b/a4401f0f.366f0fdf.js similarity index 93% rename from a4401f0f.3ce70155.js rename to a4401f0f.366f0fdf.js index a9eea8745c..341fb796d3 100644 --- a/a4401f0f.3ce70155.js +++ b/a4401f0f.366f0fdf.js @@ -1,2 +1,2 @@ -/*! For license information please see a4401f0f.3ce70155.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[178],{330: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(449)),i=n(453),c=n(456),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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.366f0fdf.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[180],{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 r=n(1),a=n(9),o=(n(0),n(451)),i=n(455),c=n(458),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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.f0934418.js.LICENSE.txt b/a4401f0f.366f0fdf.js.LICENSE.txt similarity index 100% rename from a4a09dfe.f0934418.js.LICENSE.txt rename to a4401f0f.366f0fdf.js.LICENSE.txt diff --git a/a4459aa8.696ee9c1.js b/a4459aa8.b18f40de.js similarity index 92% rename from a4459aa8.696ee9c1.js rename to a4459aa8.b18f40de.js index e841d2af06..b36411e86d 100644 --- a/a4459aa8.696ee9c1.js +++ b/a4459aa8.b18f40de.js @@ -1,2 +1,2 @@ -/*! For license information please see a4459aa8.696ee9c1.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[179],{331: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(449)),o=(t(448),t(453),t(457),{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},447: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}},452: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""}}})},453:function(e,n,t){"use strict";t(452);var a=t(0),r=t.n(a),i=t(448);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)}},454:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),c=t(458),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}))}},457:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(454),o=t(447),c=t.n(o);t(134);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)}},458: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.b18f40de.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[181],{333: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(451)),o=(t(450),t(455),t(459),{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},449: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}},454: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""}}})},455:function(e,n,t){"use strict";t(454);var a=t(0),r=t.n(a),i=t(450);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)}},456:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),c=t(460),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}))}},459:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(456),o=t(449),c=t.n(o);t(134);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)}},460: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.806fac79.js.LICENSE.txt b/a4459aa8.b18f40de.js.LICENSE.txt similarity index 100% rename from a4c8ecc0.806fac79.js.LICENSE.txt rename to a4459aa8.b18f40de.js.LICENSE.txt diff --git a/a4a09dfe.f0934418.js b/a4a09dfe.ab85823c.js similarity index 95% rename from a4a09dfe.f0934418.js rename to a4a09dfe.ab85823c.js index 1eef1e22dc..6db4ae56e6 100644 --- a/a4a09dfe.f0934418.js +++ b/a4a09dfe.ab85823c.js @@ -1,2 +1,2 @@ -/*! For license information please see a4a09dfe.f0934418.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[180],{332: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(449)),a=(t(457),t(448)),c=t(453),l={last_modified_on:"2024-07-30",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."),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.")),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/#custom-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},447: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}},452: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""}}})},453:function(e,n,t){"use strict";t(452);var r=t(0),o=t.n(r),i=t(448);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)}},454:function(e,n,t){"use strict";var r=t(1),o=t(0),i=t.n(o),a=t(39),c=t(458),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}))}},457:function(e,n,t){"use strict";var r=t(0),o=t.n(r),i=t(454),a=t(447),c=t.n(a);t(134);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)}},458: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.ab85823c.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[182],{334: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(451)),a=(t(459),t(450)),c=t(455),l={last_modified_on:"2024-07-30",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."),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.")),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/#custom-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},449: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}},454: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""}}})},455:function(e,n,t){"use strict";t(454);var r=t(0),o=t.n(r),i=t(450);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)}},456:function(e,n,t){"use strict";var r=t(1),o=t(0),i=t.n(o),a=t(39),c=t(460),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}))}},459:function(e,n,t){"use strict";var r=t(0),o=t.n(r),i=t(456),a=t(449),c=t.n(a);t(134);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)}},460: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.84ed9ceb.js.LICENSE.txt b/a4a09dfe.ab85823c.js.LICENSE.txt similarity index 100% rename from a8a9c166.84ed9ceb.js.LICENSE.txt rename to a4a09dfe.ab85823c.js.LICENSE.txt diff --git a/acaf40e9.068a73da.js b/a4c8ecc0.32b73066.js similarity index 95% rename from acaf40e9.068a73da.js rename to a4c8ecc0.32b73066.js index 31f293c957..be451297ed 100644 --- a/acaf40e9.068a73da.js +++ b/a4c8ecc0.32b73066.js @@ -1,2 +1,2 @@ -/*! For license information please see acaf40e9.068a73da.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[191],{343: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(449)),i=(n(448),n(453),n(457),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(458),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}))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(454),i=n(447),l=n.n(i);n(134);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)}},458: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.32b73066.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[183],{335: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(451)),i=(n(450),n(455),n(459),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(460),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}))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(456),i=n(449),l=n.n(i);n(134);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)}},460: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/a9994e72.bdcc7cbd.js.LICENSE.txt b/a4c8ecc0.32b73066.js.LICENSE.txt similarity index 100% rename from a9994e72.bdcc7cbd.js.LICENSE.txt rename to a4c8ecc0.32b73066.js.LICENSE.txt diff --git a/a601bb0b.75d77edb.js b/a601bb0b.62e38e2d.js similarity index 76% rename from a601bb0b.75d77edb.js rename to a601bb0b.62e38e2d.js index 9a7d4d8226..7ed58752f9 100644 --- a/a601bb0b.75d77edb.js +++ b/a601bb0b.62e38e2d.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[182],{334:function(a){a.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"installation-guide-scaleway","name":"installation_guide: scaleway","count":1,"permalink":"/guides/tags/installation-guide-scaleway"}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[184],{336:function(a){a.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"installation-guide-scaleway","name":"installation_guide: scaleway","count":1,"permalink":"/guides/tags/installation-guide-scaleway"}')}}]); \ No newline at end of file diff --git a/a81fb19d.c58c8c7f.js b/a81fb19d.f5282f4f.js similarity index 91% rename from a81fb19d.c58c8c7f.js rename to a81fb19d.f5282f4f.js index 3d0b14bd19..7b3e9d54d5 100644 --- a/a81fb19d.c58c8c7f.js +++ b/a81fb19d.f5282f4f.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[183],{335: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":41,"permalink":"/guides/tags/technology-qovery"},"installation-guide-aws":{"allTagsPath":"/guides/tags","slug":"installation-guide-aws","name":"installation_guide: aws","count":12,"permalink":"/guides/tags/installation-guide-aws"},"installation-guide-gcp":{"allTagsPath":"/guides/tags","slug":"installation-guide-gcp","name":"installation_guide: gcp","count":1,"permalink":"/guides/tags/installation-guide-gcp"},"installation-guide-scaleway":{"allTagsPath":"/guides/tags","slug":"installation-guide-scaleway","name":"installation_guide: scaleway","count":1,"permalink":"/guides/tags/installation-guide-scaleway"},"installation-guide-kubernetes":{"allTagsPath":"/guides/tags","slug":"installation-guide-kubernetes","name":"installation_guide: kubernetes","count":1,"permalink":"/guides/tags/installation-guide-kubernetes"},"installation-guide-azure":{"allTagsPath":"/guides/tags","slug":"installation-guide-azure","name":"installation_guide: azure","count":1,"permalink":"/guides/tags/installation-guide-azure"},"type-tutorial":{"allTagsPath":"/guides/tags","slug":"type-tutorial","name":"type: tutorial","count":42,"permalink":"/guides/tags/type-tutorial"},"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"},"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([[185],{337: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":42,"permalink":"/guides/tags/technology-qovery"},"installation-guide-aws":{"allTagsPath":"/guides/tags","slug":"installation-guide-aws","name":"installation_guide: aws","count":13,"permalink":"/guides/tags/installation-guide-aws"},"installation-guide-gcp":{"allTagsPath":"/guides/tags","slug":"installation-guide-gcp","name":"installation_guide: gcp","count":1,"permalink":"/guides/tags/installation-guide-gcp"},"installation-guide-scaleway":{"allTagsPath":"/guides/tags","slug":"installation-guide-scaleway","name":"installation_guide: scaleway","count":1,"permalink":"/guides/tags/installation-guide-scaleway"},"installation-guide-kubernetes":{"allTagsPath":"/guides/tags","slug":"installation-guide-kubernetes","name":"installation_guide: kubernetes","count":1,"permalink":"/guides/tags/installation-guide-kubernetes"},"installation-guide-azure":{"allTagsPath":"/guides/tags","slug":"installation-guide-azure","name":"installation_guide: azure","count":1,"permalink":"/guides/tags/installation-guide-azure"},"type-tutorial":{"allTagsPath":"/guides/tags","slug":"type-tutorial","name":"type: tutorial","count":43,"permalink":"/guides/tags/type-tutorial"},"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"},"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.ae41bdee.js b/a8a9c166.a3ba20ae.js similarity index 87% rename from da253275.ae41bdee.js rename to a8a9c166.a3ba20ae.js index 186a468823..9cb9ecdf81 100644 --- a/da253275.ae41bdee.js +++ b/a8a9c166.a3ba20ae.js @@ -1,2 +1,2 @@ -/*! For license information please see da253275.ae41bdee.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 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(449)),i=(n(456),n(453),n(448)),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(447),n(455)),i=n.n(a);n(133);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"),"."))}},459: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.a3ba20ae.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[186],{338: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(451)),i=(n(458),n(455),n(450)),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(449),n(457)),i=n.n(a);n(133);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"),"."))}},461: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/abbfd6bd.85276352.js.LICENSE.txt b/a8a9c166.a3ba20ae.js.LICENSE.txt similarity index 100% rename from abbfd6bd.85276352.js.LICENSE.txt rename to a8a9c166.a3ba20ae.js.LICENSE.txt diff --git a/bbfbe73c.83a36949.js b/a9994e72.58ee3d81.js similarity index 93% rename from bbfbe73c.83a36949.js rename to a9994e72.58ee3d81.js index a5be8cc335..6f0327a2fc 100644 --- a/bbfbe73c.83a36949.js +++ b/a9994e72.58ee3d81.js @@ -1,2 +1,2 @@ -/*! For license information please see bbfbe73c.83a36949.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[216],{367: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(449)),i=n(448),c=n(457),l=n(453),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},454:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),c=n(458),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}))}},457:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(454),i=n(447),c=n.n(i);n(134);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)}},458: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.58ee3d81.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[187],{339: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(451)),i=n(450),c=n(459),l=n(455),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},456:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),c=n(460),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}))}},459:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(456),i=n(449),c=n.n(i);n(134);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)}},460: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/ac2c90fd.026d02fe.js.LICENSE.txt b/a9994e72.58ee3d81.js.LICENSE.txt similarity index 100% rename from ac2c90fd.026d02fe.js.LICENSE.txt rename to a9994e72.58ee3d81.js.LICENSE.txt diff --git a/ab1ec509.f3d40886.js b/ab1ec509.9e600e60.js similarity index 96% rename from ab1ec509.f3d40886.js rename to ab1ec509.9e600e60.js index 4ece1e527c..b6ae614732 100644 --- a/ab1ec509.f3d40886.js +++ b/ab1ec509.9e600e60.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[186],{338:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return u})),a.d(t,"metadata",(function(){return p})),a.d(t,"rightToc",(function(){return d})),a.d(t,"default",(function(){return h}));var n,l=a(1),r=a(9),o=(a(0),a(449)),c=a(464),s=a(456),b=a(448),i=a(461),u={last_modified_on:"2024-07-12",title:"Self-Managed Cluster",description:"Learn how to install and configure Qovery on your AWS Kubernetes Service (EKS) cluster"},p={id:"getting-started/install-qovery/aws/self-managed-cluster",title:"Self-Managed Cluster",description:"Learn how to install and configure Qovery on your AWS Kubernetes Service (EKS) cluster",source:"@site/docs/getting-started/install-qovery/aws/self-managed-cluster.md",permalink:"/docs/getting-started/install-qovery/aws/self-managed-cluster",sidebar:"docs",previous:{title:"FAQ",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/faq"},next:{title:"GCP",permalink:"/docs/getting-started/install-qovery/gcp"}},d=[{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Install Qovery on your AWS EKS cluster",id:"install-qovery-on-your-aws-eks-cluster",children:[]},{value:"What's Next?",id:"whats-next",children:[]}],m=(n="Assumption",function(e){return console.warn("Component "+n+" was not imported, exported, or provided by MDXProvider as global scope"),Object(o.b)("div",e)}),y={rightToc:d};function h(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(l.a)({},y,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are not familiar with Kubernetes, we recommend you to use Qovery on a Managed Kubernetes cluster on ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/"}),"AWS"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/"}),"GCP"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/"}),"Scaleway"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart/"}),"Azure"),", or contact us.")),Object(o.b)("p",null,"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.\nRead ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/blog/kubernetes-managed-by-qovery-vs-self-managed-byok"}),"this article")," to better understand the difference with the Managed Kubernetes by Qovery. In a nutshell, Qovery 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."),Object(o.b)(b.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery automatically updates ",Object(o.b)("strong",{parentName:"p"},"ONLY")," the Qovery applications (agent, shell-agent etc..) via the Qovery Helm chart. With the self-managed offer it will be up to you to manage any dependency components (ingress, dns, logging...), making sure they run with the right version over time."),Object(o.b)("p",null,"The dependencies provided with the Qovery Helm chart are here to help you with the bootstrap, and are not maintained by Qovery. If you want to simplify the maintenance of your cluster, please look at ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/pricing/"}),"Qovery managed Kubernetes offer"),".")),Object(o.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(o.b)(m,{mdxType:"Assumption"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a AWS EKS Kubernetes cluster up and running."),Object(o.b)("li",{parentName:"ul"},"You have a AWS EKS Kubernetes cluster with at least 4 CPUs and 8GB of RAM."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"kubectl")," installed and configured to access your AWS EKS Kubernetes cluster."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"helm")," installed."),Object(o.b)("li",{parentName:"ul"},"You have a Qovery account. If you don't have one, please sign up at ",Object(o.b)("a",Object(l.a)({parentName:"li"},{href:"https://start.qovery.com"}),"https://start.qovery.com")))),Object(o.b)("h2",{id:"install-qovery-on-your-aws-eks-cluster"},"Install Qovery on your AWS EKS cluster"),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/local/"}),"this guide")," to try Qovery on your local machine.")),Object(o.b)(i.a,{centered:!0,className:"rounded",defaultValue:"automatic",placeholder:"Install Qovery",select:!1,size:null,values:[{group:"Install",label:"Automatic",value:"automatic"},{group:"Install",label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.a,{value:"automatic",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery CLI by running the following command:"),Object(o.b)(i.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)(c.a,{value:"linux",mdxType:"TabItem"},Object(o.b)(i.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.a,{value:"arch",mdxType:"TabItem"},Object(o.b)("p",null,"Qovery is part of ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"macos",mdxType:"TabItem"},Object(o.b)(i.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)(c.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(l.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"windows",mdxType:"TabItem"},Object(o.b)(i.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.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(l.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.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)(c.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(l.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(l.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(l.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)("p",null,"Authenticate with Qovery by running the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are using a headless (without GUI) environment, you can use the following command to sign up and sign in:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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 Qovery sign-up page will open. Follow the instructions to sign up and sign in.")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your AWS EKS cluster:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"qovery cluster install\n")),Object(o.b)("p",null,"Respond to the prompts to install Qovery on your AWS EKS Kubernetes cluster."))))),Object(o.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://helm.sh"}),"Helm")," command line tool.")),Object(o.b)("li",null,Object(o.b)("p",null,"Add Qovery Helm repository."),Object(o.b)(b.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery Helm Chart is only available for users who have access to Qovery BYOK. ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/bring-your-own-kubernetes"}),"Request your access here"),".")),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm repo add qovery https://helm.qovery.com\nhelm repo update\n"))),Object(o.b)("li",null,Object(o.b)("p",null,"Login to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console"),", create a cluster of type ",Object(o.b)("inlineCode",{parentName:"p"},"Self-Managed"),". At the end of the flow you will be able to download the ",Object(o.b)("inlineCode",{parentName:"p"},"values.yaml")," file associated with this cluster.")),Object(o.b)("li",null,Object(o.b)("p",null,"Now you can customize your values.yaml file based on your need. Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),"."),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Make sure that all fields having value ",Object(o.b)("inlineCode",{parentName:"p"},"set-by-customer")," are filled.")),Object(o.b)("p",null,"Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your Kubernetes cluster."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --wait --atomic --create-namespace -n qovery -f \\\n --set services.certificates.cert-manager-configs.enabled=false \\\n --set services.certificates.qovery-cert-manager-webhook.enabled=false \\\n --set services.qovery.qovery-cluster-agent.enabled=false \\\n --set services.qovery.qovery-engine.enabled=false \\\n qovery qovery/qovery\n")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-n qovery"),": the namespace where Qovery and its dependencies will be installed"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"--set..."),": override (only for the first deployment time, if you want to use Cert-Manager) to let cert-manager install its CRDs"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-f your-values-file.yaml"),": the values file you've downloaded, overrided with the Qovery config and your custom config"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery/qovery"),": name of the chart to deploy"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery"),": name of the release")),Object(o.b)("p",null,"If you want to use Cert-Manager, you can remove the ",Object(o.b)("inlineCode",{parentName:"p"},"--set...")," for the future updates (or if already installed):"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --create-namespace -n qovery -f --wait --atomic qovery qovery/qovery\n"))))))),Object(o.b)("p",null,"That's it, you can now use Qovery on your AWS EKS cluster."),Object(o.b)("p",null,"Connect to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console")," to validate that Qovery is properly installed and start deploying your applications."),Object(o.b)("h2",{id:"whats-next"},"What's Next?"),Object(o.b)("p",null,"Now that you have Qovery installed on your Kubernetes cluster, you can check that Qovery is properly installed by following the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/validate-installation/"}),"Validate Installation")," guide."))}h.isMDXComponent=!0},448:function(e,t,a){"use strict";a(450);var n=a(0),l=a.n(n),r=a(447),o=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,s=null;switch(c){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return l.a.createElement("div",{className:o()(a,"alert","alert--"+c,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&l.a.createElement("i",{className:o()("feather","icon-"+(r||s))}),t)}},456:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=(a(447),a(455)),o=a.n(r);a(133);t.a=function(e){var t=e.children,a=e.headingDepth,r=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"},b="https://github.com/qovery/documentation/issues/new?"+o.a.stringify(s),i=Object(n.useState)(null),u=i[0],p=i[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:b,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"),"."))}},461:function(e,t,a){"use strict";var n=a(1),l=(a(465),a(462),a(52),a(29),a(22),a(21),a(0)),r=a.n(l),o=a(469),c=a(447),s=a.n(c),b=a(455),i=a.n(b),u=a(468),p=37,d=39;function m(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,l=e.className,o=e.handleKeydown,c=e.style,b=e.values,i=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:s()("tabs",l,{"tabs--block":t}),style:c},b.map((function(e){var t=e.value,a=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":i===t,className:s()("tab-item",{"tab-item--active":i===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return o(u,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function y(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,l=e.size,c=e.values,s=c;if(s[0].group){var b=_.groupBy(s,"group");s=Object.keys(b).map((function(e){return{label:e,options:b[e]}}))}return r.a.createElement(o.a,{className:"react-select-container react-select--"+l,classNamePrefix:"react-select",options:s,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,o=e.groupId,c=e.label,s=e.placeholder,b=e.select,h=e.size,v=(e.style,e.values),O=e.urlKey,j=Object(u.a)(),g=j.tabGroupChoices,f=j.setTabGroupChoices,w=Object(l.useState)(a),N=w[0],q=w[1];if(null!=o){var T=g[o];null!=T&&T!==N&&q(T)}var k=function(e){q(e),null!=o&&f(o,e)},Q=[],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=i.a.parse(window.location.search);e[O]&&q(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),v.length>1&&(b?r.a.createElement(y,Object(n.a)({changeSelectedValue:k,handleKeydown:x,placeholder:s,selectedValue:N,size:h,tabRefs:Q},e)):r.a.createElement(m,Object(n.a)({changeSelectedValue:k,handleKeydown:x,selectedValue:N,tabRefs:Q},e)))),l.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},464: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([[188],{340:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return u})),a.d(t,"metadata",(function(){return p})),a.d(t,"rightToc",(function(){return d})),a.d(t,"default",(function(){return h}));var n,l=a(1),r=a(9),o=(a(0),a(451)),c=a(466),s=a(458),b=a(450),i=a(463),u={last_modified_on:"2024-07-12",title:"Self-Managed Cluster",description:"Learn how to install and configure Qovery on your AWS Kubernetes Service (EKS) cluster"},p={id:"getting-started/install-qovery/aws/self-managed-cluster",title:"Self-Managed Cluster",description:"Learn how to install and configure Qovery on your AWS Kubernetes Service (EKS) cluster",source:"@site/docs/getting-started/install-qovery/aws/self-managed-cluster.md",permalink:"/docs/getting-started/install-qovery/aws/self-managed-cluster",sidebar:"docs",previous:{title:"FAQ",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/faq"},next:{title:"GCP",permalink:"/docs/getting-started/install-qovery/gcp"}},d=[{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Install Qovery on your AWS EKS cluster",id:"install-qovery-on-your-aws-eks-cluster",children:[]},{value:"What's Next?",id:"whats-next",children:[]}],m=(n="Assumption",function(e){return console.warn("Component "+n+" was not imported, exported, or provided by MDXProvider as global scope"),Object(o.b)("div",e)}),y={rightToc:d};function h(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(l.a)({},y,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are not familiar with Kubernetes, we recommend you to use Qovery on a Managed Kubernetes cluster on ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/"}),"AWS"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/"}),"GCP"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/"}),"Scaleway"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart/"}),"Azure"),", or contact us.")),Object(o.b)("p",null,"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.\nRead ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/blog/kubernetes-managed-by-qovery-vs-self-managed-byok"}),"this article")," to better understand the difference with the Managed Kubernetes by Qovery. In a nutshell, Qovery 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."),Object(o.b)(b.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery automatically updates ",Object(o.b)("strong",{parentName:"p"},"ONLY")," the Qovery applications (agent, shell-agent etc..) via the Qovery Helm chart. With the self-managed offer it will be up to you to manage any dependency components (ingress, dns, logging...), making sure they run with the right version over time."),Object(o.b)("p",null,"The dependencies provided with the Qovery Helm chart are here to help you with the bootstrap, and are not maintained by Qovery. If you want to simplify the maintenance of your cluster, please look at ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/pricing/"}),"Qovery managed Kubernetes offer"),".")),Object(o.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(o.b)(m,{mdxType:"Assumption"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a AWS EKS Kubernetes cluster up and running."),Object(o.b)("li",{parentName:"ul"},"You have a AWS EKS Kubernetes cluster with at least 4 CPUs and 8GB of RAM."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"kubectl")," installed and configured to access your AWS EKS Kubernetes cluster."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"helm")," installed."),Object(o.b)("li",{parentName:"ul"},"You have a Qovery account. If you don't have one, please sign up at ",Object(o.b)("a",Object(l.a)({parentName:"li"},{href:"https://start.qovery.com"}),"https://start.qovery.com")))),Object(o.b)("h2",{id:"install-qovery-on-your-aws-eks-cluster"},"Install Qovery on your AWS EKS cluster"),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/local/"}),"this guide")," to try Qovery on your local machine.")),Object(o.b)(i.a,{centered:!0,className:"rounded",defaultValue:"automatic",placeholder:"Install Qovery",select:!1,size:null,values:[{group:"Install",label:"Automatic",value:"automatic"},{group:"Install",label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.a,{value:"automatic",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery CLI by running the following command:"),Object(o.b)(i.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)(c.a,{value:"linux",mdxType:"TabItem"},Object(o.b)(i.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.a,{value:"arch",mdxType:"TabItem"},Object(o.b)("p",null,"Qovery is part of ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"macos",mdxType:"TabItem"},Object(o.b)(i.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)(c.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(l.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"windows",mdxType:"TabItem"},Object(o.b)(i.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.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(l.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.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)(c.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(l.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(l.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(l.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)("p",null,"Authenticate with Qovery by running the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are using a headless (without GUI) environment, you can use the following command to sign up and sign in:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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 Qovery sign-up page will open. Follow the instructions to sign up and sign in.")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your AWS EKS cluster:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"qovery cluster install\n")),Object(o.b)("p",null,"Respond to the prompts to install Qovery on your AWS EKS Kubernetes cluster."))))),Object(o.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://helm.sh"}),"Helm")," command line tool.")),Object(o.b)("li",null,Object(o.b)("p",null,"Add Qovery Helm repository."),Object(o.b)(b.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery Helm Chart is only available for users who have access to Qovery BYOK. ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/bring-your-own-kubernetes"}),"Request your access here"),".")),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm repo add qovery https://helm.qovery.com\nhelm repo update\n"))),Object(o.b)("li",null,Object(o.b)("p",null,"Login to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console"),", create a cluster of type ",Object(o.b)("inlineCode",{parentName:"p"},"Self-Managed"),". At the end of the flow you will be able to download the ",Object(o.b)("inlineCode",{parentName:"p"},"values.yaml")," file associated with this cluster.")),Object(o.b)("li",null,Object(o.b)("p",null,"Now you can customize your values.yaml file based on your need. Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),"."),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Make sure that all fields having value ",Object(o.b)("inlineCode",{parentName:"p"},"set-by-customer")," are filled.")),Object(o.b)("p",null,"Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your Kubernetes cluster."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --wait --atomic --create-namespace -n qovery -f \\\n --set services.certificates.cert-manager-configs.enabled=false \\\n --set services.certificates.qovery-cert-manager-webhook.enabled=false \\\n --set services.qovery.qovery-cluster-agent.enabled=false \\\n --set services.qovery.qovery-engine.enabled=false \\\n qovery qovery/qovery\n")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-n qovery"),": the namespace where Qovery and its dependencies will be installed"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"--set..."),": override (only for the first deployment time, if you want to use Cert-Manager) to let cert-manager install its CRDs"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-f your-values-file.yaml"),": the values file you've downloaded, overrided with the Qovery config and your custom config"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery/qovery"),": name of the chart to deploy"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery"),": name of the release")),Object(o.b)("p",null,"If you want to use Cert-Manager, you can remove the ",Object(o.b)("inlineCode",{parentName:"p"},"--set...")," for the future updates (or if already installed):"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --create-namespace -n qovery -f --wait --atomic qovery qovery/qovery\n"))))))),Object(o.b)("p",null,"That's it, you can now use Qovery on your AWS EKS cluster."),Object(o.b)("p",null,"Connect to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console")," to validate that Qovery is properly installed and start deploying your applications."),Object(o.b)("h2",{id:"whats-next"},"What's Next?"),Object(o.b)("p",null,"Now that you have Qovery installed on your Kubernetes cluster, you can check that Qovery is properly installed by following the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/validate-installation/"}),"Validate Installation")," guide."))}h.isMDXComponent=!0},450:function(e,t,a){"use strict";a(452);var n=a(0),l=a.n(n),r=a(449),o=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,s=null;switch(c){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return l.a.createElement("div",{className:o()(a,"alert","alert--"+c,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&l.a.createElement("i",{className:o()("feather","icon-"+(r||s))}),t)}},458:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=(a(449),a(457)),o=a.n(r);a(133);t.a=function(e){var t=e.children,a=e.headingDepth,r=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"},b="https://github.com/qovery/documentation/issues/new?"+o.a.stringify(s),i=Object(n.useState)(null),u=i[0],p=i[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:b,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"),"."))}},463:function(e,t,a){"use strict";var n=a(1),l=(a(467),a(464),a(52),a(29),a(22),a(21),a(0)),r=a.n(l),o=a(471),c=a(449),s=a.n(c),b=a(457),i=a.n(b),u=a(470),p=37,d=39;function m(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,l=e.className,o=e.handleKeydown,c=e.style,b=e.values,i=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:s()("tabs",l,{"tabs--block":t}),style:c},b.map((function(e){var t=e.value,a=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":i===t,className:s()("tab-item",{"tab-item--active":i===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return o(u,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function y(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,l=e.size,c=e.values,s=c;if(s[0].group){var b=_.groupBy(s,"group");s=Object.keys(b).map((function(e){return{label:e,options:b[e]}}))}return r.a.createElement(o.a,{className:"react-select-container react-select--"+l,classNamePrefix:"react-select",options:s,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,o=e.groupId,c=e.label,s=e.placeholder,b=e.select,h=e.size,v=(e.style,e.values),O=e.urlKey,j=Object(u.a)(),g=j.tabGroupChoices,f=j.setTabGroupChoices,w=Object(l.useState)(a),N=w[0],q=w[1];if(null!=o){var T=g[o];null!=T&&T!==N&&q(T)}var k=function(e){q(e),null!=o&&f(o,e)},Q=[],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=i.a.parse(window.location.search);e[O]&&q(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),v.length>1&&(b?r.a.createElement(y,Object(n.a)({changeSelectedValue:k,handleKeydown:x,placeholder:s,selectedValue:N,size:h,tabRefs:Q},e)):r.a.createElement(m,Object(n.a)({changeSelectedValue:k,handleKeydown:x,selectedValue:N,tabRefs:Q},e)))),l.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},466: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/f7098925.1e368698.js b/ab8f5b83.6779fce9.js similarity index 96% rename from f7098925.1e368698.js rename to ab8f5b83.6779fce9.js index 55f9ac7cd4..871d838bd0 100644 --- a/f7098925.1e368698.js +++ b/ab8f5b83.6779fce9.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[282],{434: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(449)),i=n(448),l=n(457),s=n(456),c=n(461),b=n(464),u=n(453),p={last_modified_on:"2024-05-03",$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://console.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.png",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 a headless (without GUI) environment, you can use the following command to sign up and sign in:"),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 Qovery sign-up page will open. Follow the instructions to sign up and sign 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},448:function(e,t,n){"use strict";n(450);var a=n(0),r=n.n(a),o=n(447),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)}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(458),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}))}},456:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(454),i=n(447),l=n.n(i);n(134);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)}},458:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},461:function(e,t,n){"use strict";var a=n(1),r=(n(465),n(462),n(52),n(29),n(22),n(21),n(0)),o=n.n(r),i=n(469),l=n(447),s=n.n(l),c=n(455),b=n.n(c),u=n(468),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])}},464: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([[189],{341: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(451)),i=n(450),l=n(459),s=n(458),c=n(463),b=n(466),u=n(455),p={last_modified_on:"2024-05-03",$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://console.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.png",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 a headless (without GUI) environment, you can use the following command to sign up and sign in:"),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 Qovery sign-up page will open. Follow the instructions to sign up and sign 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},450:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(449),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)}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(460),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}))}},458:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(456),i=n(449),l=n.n(i);n(134);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)}},460:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},463:function(e,t,n){"use strict";var a=n(1),r=(n(467),n(464),n(52),n(29),n(22),n(21),n(0)),o=n.n(r),i=n(471),l=n(449),s=n.n(l),c=n(457),b=n.n(c),u=n(470),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])}},466: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/abbfd6bd.85276352.js b/abbfd6bd.efedb6d5.js similarity index 93% rename from abbfd6bd.85276352.js rename to abbfd6bd.efedb6d5.js index 28b287395e..06583f3801 100644 --- a/abbfd6bd.85276352.js +++ b/abbfd6bd.efedb6d5.js @@ -1,2 +1,2 @@ -/*! For license information please see abbfd6bd.85276352.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[188],{340:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return c})),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(449)),i=n(456),l=n(453),u={last_modified_on:"2024-07-19",$schema:"/.meta/.schemas/guides.json",title:"Deploy JupyterHub using Helm",description:"How to deploy JupyterHub on Qovery using the official Helm chart.",author_github:"https://github.com/baalooos",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:"Deploy JupyterHub using Helm",description:"How to deploy JupyterHub on Qovery using the official Helm chart.",permalink:"/guides/tutorial/deploy-jupyterhub-qovery",readingTime:"3 min read",source:"@site/guides/tutorial/deploy-jupyterhub-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Deploy JupyterHub using Helm",truncated:!1,prevItem:{title:"Deploy Frontend App",permalink:"/guides/advanced/deploy-frontend"},nextItem:{title:"Deploy Rails with PostgreSQL and Sidekiq",permalink:"/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq"}},s=[{value:"Installation",id:"installation",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],p={rightToc:s};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,"JupyterHub is an easy way to interact with a computing environment through a webpage. It provides a standardized way to serve Jupyter Notebooks for multiple users. Pairing it with Kubernetes and Qovery makes it easier to manage and scale."),Object(o.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a Qovery cluster ready"),Object(o.b)("li",{parentName:"ul"},"You have a dedicated Qovery project and environment to deploy JupyterHub (example: Project=JupyterHub, Environment=Production)"))),Object(o.b)("h2",{id:"installation"},"Installation"),Object(o.b)("p",null,"The easiest way to deploy JupyterHub is using the official ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/jupyterhub/helm-chart"}),"Helm Chart"),". It will create all the resources you need to run JupyterHub."),Object(o.b)("p",null,"For more information, the official documentation is available ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://z2jh.jupyter.org/en/stable/jupyterhub/installation.html"}),"here"),"."),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"add-the-jupyterhub-helm-repository"},"Add the JupyterHub helm repository"),Object(o.b)("p",null,"Add the JupyterHub helm repository in your Qovery settings by following ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/helm-repository/"}),"this documentation")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Repository name: ",Object(o.b)("inlineCode",{parentName:"li"},"JupyterHub")),Object(o.b)("li",{parentName:"ul"},"Kind: ",Object(o.b)("inlineCode",{parentName:"li"},"HTTPS")),Object(o.b)("li",{parentName:"ul"},"Repository URL: ",Object(o.b)("inlineCode",{parentName:"li"},"https://hub.jupyter.org/helm-chart/")))),Object(o.b)("li",null,Object(o.b)("h4",{id:"create-the-jupyterhub-service-within-qovery"},"Create the JupyterHub service within Qovery"),Object(o.b)("p",null,"Create the JupyterHub service in the Qovery environment of your choice (preferably within a dedicated JupyterHub project) by following ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/"}),"this documentation")," and these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"General:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Application name: ",Object(o.b)("inlineCode",{parentName:"li"},"JupyterHub")),Object(o.b)("li",{parentName:"ul"},"Source:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Helm source: ",Object(o.b)("inlineCode",{parentName:"li"},"Helm repository")),Object(o.b)("li",{parentName:"ul"},"Repository: ",Object(o.b)("inlineCode",{parentName:"li"},"JupyterHub")," (the name given during the JupyterHub helm repository added in the previous step)"),Object(o.b)("li",{parentName:"ul"},"Chart name: ",Object(o.b)("inlineCode",{parentName:"li"},"jupyterhub")),Object(o.b)("li",{parentName:"ul"},"Version: ",Object(o.b)("inlineCode",{parentName:"li"},"3.3.7")," (this is the version we used for this setup, update it based on the chosen version)"),Object(o.b)("li",{parentName:"ul"},"Allow cluster-wide resources \u2714\ufe0f"))))),Object(o.b)("li",{parentName:"ul"},"Values",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Values override as file:"),Object(o.b)("li",{parentName:"ul"},"File source: ",Object(o.b)("inlineCode",{parentName:"li"},"Raw YAML")),Object(o.b)("li",{parentName:"ul"},"Raw YAML:")))),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-yaml"}),'fullnameOverride: "jupyterhub"\nproxy:\n service:\n type: ClusterIP\n')),Object(o.b)("p",null,"There are many other values you can set to modify the JupyterHub behavior. For advanced usage, check: ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://z2jh.jupyter.org/en/stable/jupyterhub/customization.html"}),"JupyterHub Customization")),Object(o.b)("p",null,"Now get to the last step and ",Object(o.b)("inlineCode",{parentName:"p"},"Create")," the service on Qovery.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"add-network-configuration"},"Add Network configuration"),Object(o.b)("p",null,"In the previous step, we created the JupyterHub service. In this step, we will update its configuration to make it available on the public network (through Qovery Nginx Ingress)."),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Open the JupyterHub service details"),Object(o.b)("li",{parentName:"ul"},"Enter the ",Object(o.b)("inlineCode",{parentName:"li"},"Settings")," section"),Object(o.b)("li",{parentName:"ul"},"Click on ",Object(o.b)("inlineCode",{parentName:"li"},"Networking")),Object(o.b)("li",{parentName:"ul"},"Add a new Port with:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Service name: jupyterhub-proxy-public"),Object(o.b)("li",{parentName:"ul"},"Service port: 80"),Object(o.b)("li",{parentName:"ul"},"Select protocol: HTTP"),Object(o.b)("li",{parentName:"ul"},"External port: 443"),Object(o.b)("li",{parentName:"ul"},"Port name: jupyterhub-proxy-public-p80")))),Object(o.b)("p",null,"If you need more information on how to manage your ports, have a look at ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/application/#ports"}),"this"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"deploy-your-chart"},"Deploy your chart"),Object(o.b)("p",null,"Open the ",Object(o.b)("inlineCode",{parentName:"p"},"Play")," button and trigger the deployment of your chart."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deploy-jupyterhub-qovery/deploy.png",alt:"JupyterHub - Deploy"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"access-jupyterhub"},"Access JupyterHub"),Object(o.b)("p",null,"You can click the ",Object(o.b)("inlineCode",{parentName:"p"},"Link")," button to access JupyterHub on your cluster."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deploy-jupyterhub-qovery/link.png",alt:"JupyterHub - Link"})),Object(o.b)("p",null,"Now you can login to the webUI and start playing with Jupyter Notebooks.")))),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"JupyterHub is running on your Qovery cluster. This is a simple installation and you should try to ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://z2jh.jupyter.org/en/stable/jupyterhub/customization.html"}),"customize")," it according to your needs. You can also check the",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://z2jh.jupyter.org/en/stable/administrator/index.html"}),"Adminstrator Guide"),"to better understand how it works."))}b.isMDXComponent=!0},447: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 c=a.a.createContext({}),s=function(e){var t=a.a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},p=function(e){var t=s(e.components);return a.a.createElement(c.Provider,{value:t},e.children)},b={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,c=u(e,["components","mdxType","originalType","parentName"]),p=s(n),m=r,d=p["".concat(i,".").concat(m)]||p[m]||b[m]||o;return n?a.a.createElement(d,l({ref:t},c,{components:n})):a.a.createElement(d,l({ref:t},c))}));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 l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l.mdxType="string"==typeof e?e:r,i[1]=l;for(var c=2;c1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,c=void 0===u?n:a(u,n);c>l;)t[l++]=e;return t}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,u={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(u),s=Object(r.useState)(null),p=s[0],b=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 b("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:c,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"),"."))}},459: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 abbfd6bd.efedb6d5.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[190],{342:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return u})),n.d(t,"metadata",(function(){return c})),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(451)),i=n(458),l=n(455),u={last_modified_on:"2024-07-19",$schema:"/.meta/.schemas/guides.json",title:"Deploy JupyterHub using Helm",description:"How to deploy JupyterHub on Qovery using the official Helm chart.",author_github:"https://github.com/baalooos",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:"Deploy JupyterHub using Helm",description:"How to deploy JupyterHub on Qovery using the official Helm chart.",permalink:"/guides/tutorial/deploy-jupyterhub-qovery",readingTime:"3 min read",source:"@site/guides/tutorial/deploy-jupyterhub-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Deploy JupyterHub using Helm",truncated:!1,prevItem:{title:"Deploy Frontend App",permalink:"/guides/advanced/deploy-frontend"},nextItem:{title:"Deploy Rails with PostgreSQL and Sidekiq",permalink:"/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq"}},s=[{value:"Installation",id:"installation",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],p={rightToc:s};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,"JupyterHub is an easy way to interact with a computing environment through a webpage. It provides a standardized way to serve Jupyter Notebooks for multiple users. Pairing it with Kubernetes and Qovery makes it easier to manage and scale."),Object(o.b)(l.a,{name:"guide",mdxType:"Assumptions"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a Qovery cluster ready"),Object(o.b)("li",{parentName:"ul"},"You have a dedicated Qovery project and environment to deploy JupyterHub (example: Project=JupyterHub, Environment=Production)"))),Object(o.b)("h2",{id:"installation"},"Installation"),Object(o.b)("p",null,"The easiest way to deploy JupyterHub is using the official ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/jupyterhub/helm-chart"}),"Helm Chart"),". It will create all the resources you need to run JupyterHub."),Object(o.b)("p",null,"For more information, the official documentation is available ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://z2jh.jupyter.org/en/stable/jupyterhub/installation.html"}),"here"),"."),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"add-the-jupyterhub-helm-repository"},"Add the JupyterHub helm repository"),Object(o.b)("p",null,"Add the JupyterHub helm repository in your Qovery settings by following ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/helm-repository/"}),"this documentation")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Repository name: ",Object(o.b)("inlineCode",{parentName:"li"},"JupyterHub")),Object(o.b)("li",{parentName:"ul"},"Kind: ",Object(o.b)("inlineCode",{parentName:"li"},"HTTPS")),Object(o.b)("li",{parentName:"ul"},"Repository URL: ",Object(o.b)("inlineCode",{parentName:"li"},"https://hub.jupyter.org/helm-chart/")))),Object(o.b)("li",null,Object(o.b)("h4",{id:"create-the-jupyterhub-service-within-qovery"},"Create the JupyterHub service within Qovery"),Object(o.b)("p",null,"Create the JupyterHub service in the Qovery environment of your choice (preferably within a dedicated JupyterHub project) by following ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/"}),"this documentation")," and these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"General:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Application name: ",Object(o.b)("inlineCode",{parentName:"li"},"JupyterHub")),Object(o.b)("li",{parentName:"ul"},"Source:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Helm source: ",Object(o.b)("inlineCode",{parentName:"li"},"Helm repository")),Object(o.b)("li",{parentName:"ul"},"Repository: ",Object(o.b)("inlineCode",{parentName:"li"},"JupyterHub")," (the name given during the JupyterHub helm repository added in the previous step)"),Object(o.b)("li",{parentName:"ul"},"Chart name: ",Object(o.b)("inlineCode",{parentName:"li"},"jupyterhub")),Object(o.b)("li",{parentName:"ul"},"Version: ",Object(o.b)("inlineCode",{parentName:"li"},"3.3.7")," (this is the version we used for this setup, update it based on the chosen version)"),Object(o.b)("li",{parentName:"ul"},"Allow cluster-wide resources \u2714\ufe0f"))))),Object(o.b)("li",{parentName:"ul"},"Values",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Values override as file:"),Object(o.b)("li",{parentName:"ul"},"File source: ",Object(o.b)("inlineCode",{parentName:"li"},"Raw YAML")),Object(o.b)("li",{parentName:"ul"},"Raw YAML:")))),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-yaml"}),'fullnameOverride: "jupyterhub"\nproxy:\n service:\n type: ClusterIP\n')),Object(o.b)("p",null,"There are many other values you can set to modify the JupyterHub behavior. For advanced usage, check: ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://z2jh.jupyter.org/en/stable/jupyterhub/customization.html"}),"JupyterHub Customization")),Object(o.b)("p",null,"Now get to the last step and ",Object(o.b)("inlineCode",{parentName:"p"},"Create")," the service on Qovery.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"add-network-configuration"},"Add Network configuration"),Object(o.b)("p",null,"In the previous step, we created the JupyterHub service. In this step, we will update its configuration to make it available on the public network (through Qovery Nginx Ingress)."),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Open the JupyterHub service details"),Object(o.b)("li",{parentName:"ul"},"Enter the ",Object(o.b)("inlineCode",{parentName:"li"},"Settings")," section"),Object(o.b)("li",{parentName:"ul"},"Click on ",Object(o.b)("inlineCode",{parentName:"li"},"Networking")),Object(o.b)("li",{parentName:"ul"},"Add a new Port with:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Service name: jupyterhub-proxy-public"),Object(o.b)("li",{parentName:"ul"},"Service port: 80"),Object(o.b)("li",{parentName:"ul"},"Select protocol: HTTP"),Object(o.b)("li",{parentName:"ul"},"External port: 443"),Object(o.b)("li",{parentName:"ul"},"Port name: jupyterhub-proxy-public-p80")))),Object(o.b)("p",null,"If you need more information on how to manage your ports, have a look at ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://hub.qovery.com/docs/using-qovery/configuration/application/#ports"}),"this"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"deploy-your-chart"},"Deploy your chart"),Object(o.b)("p",null,"Open the ",Object(o.b)("inlineCode",{parentName:"p"},"Play")," button and trigger the deployment of your chart."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deploy-jupyterhub-qovery/deploy.png",alt:"JupyterHub - Deploy"}))),Object(o.b)("li",null,Object(o.b)("h4",{id:"access-jupyterhub"},"Access JupyterHub"),Object(o.b)("p",null,"You can click the ",Object(o.b)("inlineCode",{parentName:"p"},"Link")," button to access JupyterHub on your cluster."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deploy-jupyterhub-qovery/link.png",alt:"JupyterHub - Link"})),Object(o.b)("p",null,"Now you can login to the webUI and start playing with Jupyter Notebooks.")))),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"JupyterHub is running on your Qovery cluster. This is a simple installation and you should try to ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://z2jh.jupyter.org/en/stable/jupyterhub/customization.html"}),"customize")," it according to your needs. You can also check the",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"https://z2jh.jupyter.org/en/stable/administrator/index.html"}),"Adminstrator Guide"),"to better understand how it works."))}b.isMDXComponent=!0},449: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 c=a.a.createContext({}),s=function(e){var t=a.a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):l({},t,{},e)),n},p=function(e){var t=s(e.components);return a.a.createElement(c.Provider,{value:t},e.children)},b={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,c=u(e,["components","mdxType","originalType","parentName"]),p=s(n),m=r,d=p["".concat(i,".").concat(m)]||p[m]||b[m]||o;return n?a.a.createElement(d,l({ref:t},c,{components:n})):a.a.createElement(d,l({ref:t},c))}));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 l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l.mdxType="string"==typeof e?e:r,i[1]=l;for(var c=2;c1?arguments[1]:void 0,n),u=i>2?arguments[2]:void 0,c=void 0===u?n:a(u,n);c>l;)t[l++]=e;return t}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);t.a=function(e){var t=e.children,n=e.headingDepth,o=e.hideFeedbackQuestion,l="undefined"!=typeof window?window.location:null,u={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(u),s=Object(r.useState)(null),p=s[0],b=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 b("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:c,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"),"."))}},461: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/acaf40e9.068a73da.js.LICENSE.txt b/abbfd6bd.efedb6d5.js.LICENSE.txt similarity index 100% rename from acaf40e9.068a73da.js.LICENSE.txt rename to abbfd6bd.efedb6d5.js.LICENSE.txt diff --git a/ac0a13b6.f46a7c64.js b/ac0a13b6.780535db.js similarity index 96% rename from ac0a13b6.f46a7c64.js rename to ac0a13b6.780535db.js index 198f78fee0..d1b4ec7c50 100644 --- a/ac0a13b6.f46a7c64.js +++ b/ac0a13b6.780535db.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[189],{341:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),a.d(t,"metadata",(function(){return p})),a.d(t,"rightToc",(function(){return d})),a.d(t,"default",(function(){return h}));var n,l=a(1),r=a(9),o=(a(0),a(449)),c=a(464),s=a(456),u=a(448),b=a(461),i={last_modified_on:"2024-07-12",title:"Self-Managed Cluster",description:"Learn how to install and configure Qovery on your Azure Kubernetes Service (AKS) cluster"},p={id:"getting-started/install-qovery/azure/self-managed-cluster",title:"Self-Managed Cluster",description:"Learn how to install and configure Qovery on your Azure Kubernetes Service (AKS) cluster",source:"@site/docs/getting-started/install-qovery/azure/self-managed-cluster.md",permalink:"/docs/getting-started/install-qovery/azure/self-managed-cluster",sidebar:"docs",previous:{title:"Quickstart",permalink:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart"},next:{title:"Kubernetes",permalink:"/docs/getting-started/install-qovery/kubernetes"}},d=[{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Install Qovery on your Azure AKS cluster",id:"install-qovery-on-your-azure-aks-cluster",children:[]},{value:"What's Next?",id:"whats-next",children:[]}],m=(n="Assumption",function(e){return console.warn("Component "+n+" was not imported, exported, or provided by MDXProvider as global scope"),Object(o.b)("div",e)}),y={rightToc:d};function h(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(l.a)({},y,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)(u.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are not familiar with Kubernetes, we recommend you to use Qovery on a Managed Kubernetes cluster on ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/"}),"AWS"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/"}),"GCP"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/"}),"Scaleway"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart/"}),"Azure"),", or contact us.")),Object(o.b)("p",null,"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.\nRead ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/blog/kubernetes-managed-by-qovery-vs-self-managed-byok"}),"this article")," to better understand the difference with the Managed Kubernetes by Qovery. In a nutshell, Qovery 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."),Object(o.b)(u.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery automatically updates ",Object(o.b)("strong",{parentName:"p"},"ONLY")," the Qovery applications (agent, shell-agent etc..) via the Qovery Helm chart. With the self-managed offer it will be up to you to manage any dependency components (ingress, dns, logging...), making sure they run with the right version over time."),Object(o.b)("p",null,"The dependencies provided with the Qovery Helm chart are here to help you with the bootstrap, and are not maintained by Qovery. If you want to simplify the maintenance of your cluster, please look at ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/pricing/"}),"Qovery managed Kubernetes offer"),".")),Object(o.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(o.b)(m,{mdxType:"Assumption"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a Azure AKS Kubernetes cluster up and running."),Object(o.b)("li",{parentName:"ul"},"You have a Azure AKS Kubernetes cluster with at least 4 CPUs and 8GB of RAM."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"kubectl")," installed and configured to access your Azure AKS Kubernetes cluster."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"helm")," installed."),Object(o.b)("li",{parentName:"ul"},"You have a Qovery account. If you don't have one, please sign up at ",Object(o.b)("a",Object(l.a)({parentName:"li"},{href:"https://start.qovery.com"}),"https://start.qovery.com")))),Object(o.b)("h2",{id:"install-qovery-on-your-azure-aks-cluster"},"Install Qovery on your Azure AKS cluster"),Object(o.b)(u.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/local/"}),"this guide")," to try Qovery on your local machine.")),Object(o.b)(b.a,{centered:!0,className:"rounded",defaultValue:"automatic",placeholder:"Install Qovery",select:!1,size:null,values:[{group:"Install",label:"Automatic",value:"automatic"},{group:"Install",label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.a,{value:"automatic",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery CLI by running the following command:"),Object(o.b)(b.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)(c.a,{value:"linux",mdxType:"TabItem"},Object(o.b)(b.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.a,{value:"arch",mdxType:"TabItem"},Object(o.b)("p",null,"Qovery is part of ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"macos",mdxType:"TabItem"},Object(o.b)(b.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)(c.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(l.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"windows",mdxType:"TabItem"},Object(o.b)(b.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.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(l.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.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)(c.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(l.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(l.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(l.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)("p",null,"Authenticate with Qovery by running the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(o.b)(u.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are using a headless (without GUI) environment, you can use the following command to sign up and sign in:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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 Qovery sign-up page will open. Follow the instructions to sign up and sign in.")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your Azure AKS cluster:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"qovery cluster install\n")),Object(o.b)("p",null,"Respond to the prompts to install Qovery on your Azure AKS Kubernetes cluster."))))),Object(o.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://helm.sh"}),"Helm")," command line tool.")),Object(o.b)("li",null,Object(o.b)("p",null,"Add Qovery Helm repository."),Object(o.b)(u.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery Helm Chart is only available for users who have access to Qovery BYOK. ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/bring-your-own-kubernetes"}),"Request your access here"),".")),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm repo add qovery https://helm.qovery.com\nhelm repo update\n"))),Object(o.b)("li",null,Object(o.b)("p",null,"Login to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console"),", create a cluster of type ",Object(o.b)("inlineCode",{parentName:"p"},"Self-Managed"),". At the end of the flow you will be able to download the ",Object(o.b)("inlineCode",{parentName:"p"},"values.yaml")," file associated with this cluster.")),Object(o.b)("li",null,Object(o.b)("p",null,"Now you can customize your values.yaml file based on your need. Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),"."),Object(o.b)(u.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Make sure that all fields having value ",Object(o.b)("inlineCode",{parentName:"p"},"set-by-customer")," are filled.")),Object(o.b)("p",null,"Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your Kubernetes cluster."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --wait --atomic --create-namespace -n qovery -f \\\n --set services.certificates.cert-manager-configs.enabled=false \\\n --set services.certificates.qovery-cert-manager-webhook.enabled=false \\\n --set services.qovery.qovery-cluster-agent.enabled=false \\\n --set services.qovery.qovery-engine.enabled=false \\\n qovery qovery/qovery\n")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-n qovery"),": the namespace where Qovery and its dependencies will be installed"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"--set..."),": override (only for the first deployment time, if you want to use Cert-Manager) to let cert-manager install its CRDs"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-f your-values-file.yaml"),": the values file you've downloaded, overrided with the Qovery config and your custom config"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery/qovery"),": name of the chart to deploy"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery"),": name of the release")),Object(o.b)("p",null,"If you want to use Cert-Manager, you can remove the ",Object(o.b)("inlineCode",{parentName:"p"},"--set...")," for the future updates (or if already installed):"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --create-namespace -n qovery -f --wait --atomic qovery qovery/qovery\n"))))))),Object(o.b)("p",null,"That's it, you can now use Qovery on your Azure AKS cluster."),Object(o.b)("p",null,"Connect to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console")," to validate that Qovery is properly installed and start deploying your applications."),Object(o.b)("h2",{id:"whats-next"},"What's Next?"),Object(o.b)("p",null,"Now that you have Qovery installed on your Kubernetes cluster, you can check that Qovery is properly installed by following the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/validate-installation/"}),"Validate Installation")," guide."))}h.isMDXComponent=!0},448:function(e,t,a){"use strict";a(450);var n=a(0),l=a.n(n),r=a(447),o=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,s=null;switch(c){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return l.a.createElement("div",{className:o()(a,"alert","alert--"+c,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&l.a.createElement("i",{className:o()("feather","icon-"+(r||s))}),t)}},456:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=(a(447),a(455)),o=a.n(r);a(133);t.a=function(e){var t=e.children,a=e.headingDepth,r=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?"+o.a.stringify(s),b=Object(n.useState)(null),i=b[0],p=b[1];return l.a.createElement("div",{className:"steps steps--h"+a},t,!r&&!i&&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:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==i&&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"),"."))}},461:function(e,t,a){"use strict";var n=a(1),l=(a(465),a(462),a(52),a(29),a(22),a(21),a(0)),r=a.n(l),o=a(469),c=a(447),s=a.n(c),u=a(455),b=a.n(u),i=a(468),p=37,d=39;function m(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,l=e.className,o=e.handleKeydown,c=e.style,u=e.values,b=e.selectedValue,i=e.tabRefs;return r.a.createElement("div",{className:a?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:s()("tabs",l,{"tabs--block":t}),style:c},u.map((function(e){var t=e.value,a=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 i.push(e)},onKeyDown:function(e){return o(i,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function y(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,l=e.size,c=e.values,s=c;if(s[0].group){var u=_.groupBy(s,"group");s=Object.keys(u).map((function(e){return{label:e,options:u[e]}}))}return r.a.createElement(o.a,{className:"react-select-container react-select--"+l,classNamePrefix:"react-select",options:s,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,o=e.groupId,c=e.label,s=e.placeholder,u=e.select,h=e.size,v=(e.style,e.values),O=e.urlKey,j=Object(i.a)(),g=j.tabGroupChoices,f=j.setTabGroupChoices,w=Object(l.useState)(a),N=w[0],q=w[1];if(null!=o){var T=g[o];null!=T&&T!==N&&q(T)}var k=function(e){q(e),null!=o&&f(o,e)},Q=[],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]&&q(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),v.length>1&&(u?r.a.createElement(y,Object(n.a)({changeSelectedValue:k,handleKeydown:x,placeholder:s,selectedValue:N,size:h,tabRefs:Q},e)):r.a.createElement(m,Object(n.a)({changeSelectedValue:k,handleKeydown:x,selectedValue:N,tabRefs:Q},e)))),l.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},464: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([[191],{343:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),a.d(t,"metadata",(function(){return p})),a.d(t,"rightToc",(function(){return d})),a.d(t,"default",(function(){return h}));var n,l=a(1),r=a(9),o=(a(0),a(451)),c=a(466),s=a(458),u=a(450),b=a(463),i={last_modified_on:"2024-07-12",title:"Self-Managed Cluster",description:"Learn how to install and configure Qovery on your Azure Kubernetes Service (AKS) cluster"},p={id:"getting-started/install-qovery/azure/self-managed-cluster",title:"Self-Managed Cluster",description:"Learn how to install and configure Qovery on your Azure Kubernetes Service (AKS) cluster",source:"@site/docs/getting-started/install-qovery/azure/self-managed-cluster.md",permalink:"/docs/getting-started/install-qovery/azure/self-managed-cluster",sidebar:"docs",previous:{title:"Quickstart",permalink:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart"},next:{title:"Kubernetes",permalink:"/docs/getting-started/install-qovery/kubernetes"}},d=[{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Install Qovery on your Azure AKS cluster",id:"install-qovery-on-your-azure-aks-cluster",children:[]},{value:"What's Next?",id:"whats-next",children:[]}],m=(n="Assumption",function(e){return console.warn("Component "+n+" was not imported, exported, or provided by MDXProvider as global scope"),Object(o.b)("div",e)}),y={rightToc:d};function h(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(l.a)({},y,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)(u.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are not familiar with Kubernetes, we recommend you to use Qovery on a Managed Kubernetes cluster on ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/"}),"AWS"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/"}),"GCP"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/"}),"Scaleway"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart/"}),"Azure"),", or contact us.")),Object(o.b)("p",null,"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.\nRead ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/blog/kubernetes-managed-by-qovery-vs-self-managed-byok"}),"this article")," to better understand the difference with the Managed Kubernetes by Qovery. In a nutshell, Qovery 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."),Object(o.b)(u.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery automatically updates ",Object(o.b)("strong",{parentName:"p"},"ONLY")," the Qovery applications (agent, shell-agent etc..) via the Qovery Helm chart. With the self-managed offer it will be up to you to manage any dependency components (ingress, dns, logging...), making sure they run with the right version over time."),Object(o.b)("p",null,"The dependencies provided with the Qovery Helm chart are here to help you with the bootstrap, and are not maintained by Qovery. If you want to simplify the maintenance of your cluster, please look at ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/pricing/"}),"Qovery managed Kubernetes offer"),".")),Object(o.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(o.b)(m,{mdxType:"Assumption"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a Azure AKS Kubernetes cluster up and running."),Object(o.b)("li",{parentName:"ul"},"You have a Azure AKS Kubernetes cluster with at least 4 CPUs and 8GB of RAM."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"kubectl")," installed and configured to access your Azure AKS Kubernetes cluster."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"helm")," installed."),Object(o.b)("li",{parentName:"ul"},"You have a Qovery account. If you don't have one, please sign up at ",Object(o.b)("a",Object(l.a)({parentName:"li"},{href:"https://start.qovery.com"}),"https://start.qovery.com")))),Object(o.b)("h2",{id:"install-qovery-on-your-azure-aks-cluster"},"Install Qovery on your Azure AKS cluster"),Object(o.b)(u.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/local/"}),"this guide")," to try Qovery on your local machine.")),Object(o.b)(b.a,{centered:!0,className:"rounded",defaultValue:"automatic",placeholder:"Install Qovery",select:!1,size:null,values:[{group:"Install",label:"Automatic",value:"automatic"},{group:"Install",label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.a,{value:"automatic",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery CLI by running the following command:"),Object(o.b)(b.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)(c.a,{value:"linux",mdxType:"TabItem"},Object(o.b)(b.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.a,{value:"arch",mdxType:"TabItem"},Object(o.b)("p",null,"Qovery is part of ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"macos",mdxType:"TabItem"},Object(o.b)(b.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)(c.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(l.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"windows",mdxType:"TabItem"},Object(o.b)(b.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.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(l.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.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)(c.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(l.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(l.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(l.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)("p",null,"Authenticate with Qovery by running the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(o.b)(u.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are using a headless (without GUI) environment, you can use the following command to sign up and sign in:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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 Qovery sign-up page will open. Follow the instructions to sign up and sign in.")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your Azure AKS cluster:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"qovery cluster install\n")),Object(o.b)("p",null,"Respond to the prompts to install Qovery on your Azure AKS Kubernetes cluster."))))),Object(o.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://helm.sh"}),"Helm")," command line tool.")),Object(o.b)("li",null,Object(o.b)("p",null,"Add Qovery Helm repository."),Object(o.b)(u.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery Helm Chart is only available for users who have access to Qovery BYOK. ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/bring-your-own-kubernetes"}),"Request your access here"),".")),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm repo add qovery https://helm.qovery.com\nhelm repo update\n"))),Object(o.b)("li",null,Object(o.b)("p",null,"Login to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console"),", create a cluster of type ",Object(o.b)("inlineCode",{parentName:"p"},"Self-Managed"),". At the end of the flow you will be able to download the ",Object(o.b)("inlineCode",{parentName:"p"},"values.yaml")," file associated with this cluster.")),Object(o.b)("li",null,Object(o.b)("p",null,"Now you can customize your values.yaml file based on your need. Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),"."),Object(o.b)(u.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Make sure that all fields having value ",Object(o.b)("inlineCode",{parentName:"p"},"set-by-customer")," are filled.")),Object(o.b)("p",null,"Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your Kubernetes cluster."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --wait --atomic --create-namespace -n qovery -f \\\n --set services.certificates.cert-manager-configs.enabled=false \\\n --set services.certificates.qovery-cert-manager-webhook.enabled=false \\\n --set services.qovery.qovery-cluster-agent.enabled=false \\\n --set services.qovery.qovery-engine.enabled=false \\\n qovery qovery/qovery\n")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-n qovery"),": the namespace where Qovery and its dependencies will be installed"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"--set..."),": override (only for the first deployment time, if you want to use Cert-Manager) to let cert-manager install its CRDs"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-f your-values-file.yaml"),": the values file you've downloaded, overrided with the Qovery config and your custom config"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery/qovery"),": name of the chart to deploy"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery"),": name of the release")),Object(o.b)("p",null,"If you want to use Cert-Manager, you can remove the ",Object(o.b)("inlineCode",{parentName:"p"},"--set...")," for the future updates (or if already installed):"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --create-namespace -n qovery -f --wait --atomic qovery qovery/qovery\n"))))))),Object(o.b)("p",null,"That's it, you can now use Qovery on your Azure AKS cluster."),Object(o.b)("p",null,"Connect to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console")," to validate that Qovery is properly installed and start deploying your applications."),Object(o.b)("h2",{id:"whats-next"},"What's Next?"),Object(o.b)("p",null,"Now that you have Qovery installed on your Kubernetes cluster, you can check that Qovery is properly installed by following the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/validate-installation/"}),"Validate Installation")," guide."))}h.isMDXComponent=!0},450:function(e,t,a){"use strict";a(452);var n=a(0),l=a.n(n),r=a(449),o=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,s=null;switch(c){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return l.a.createElement("div",{className:o()(a,"alert","alert--"+c,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&l.a.createElement("i",{className:o()("feather","icon-"+(r||s))}),t)}},458:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=(a(449),a(457)),o=a.n(r);a(133);t.a=function(e){var t=e.children,a=e.headingDepth,r=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?"+o.a.stringify(s),b=Object(n.useState)(null),i=b[0],p=b[1];return l.a.createElement("div",{className:"steps steps--h"+a},t,!r&&!i&&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:u,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==i&&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"),"."))}},463:function(e,t,a){"use strict";var n=a(1),l=(a(467),a(464),a(52),a(29),a(22),a(21),a(0)),r=a.n(l),o=a(471),c=a(449),s=a.n(c),u=a(457),b=a.n(u),i=a(470),p=37,d=39;function m(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,l=e.className,o=e.handleKeydown,c=e.style,u=e.values,b=e.selectedValue,i=e.tabRefs;return r.a.createElement("div",{className:a?"tabs--centered":null},r.a.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:s()("tabs",l,{"tabs--block":t}),style:c},u.map((function(e){var t=e.value,a=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 i.push(e)},onKeyDown:function(e){return o(i,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function y(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,l=e.size,c=e.values,s=c;if(s[0].group){var u=_.groupBy(s,"group");s=Object.keys(u).map((function(e){return{label:e,options:u[e]}}))}return r.a.createElement(o.a,{className:"react-select-container react-select--"+l,classNamePrefix:"react-select",options:s,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,o=e.groupId,c=e.label,s=e.placeholder,u=e.select,h=e.size,v=(e.style,e.values),O=e.urlKey,j=Object(i.a)(),g=j.tabGroupChoices,f=j.setTabGroupChoices,w=Object(l.useState)(a),N=w[0],q=w[1];if(null!=o){var T=g[o];null!=T&&T!==N&&q(T)}var k=function(e){q(e),null!=o&&f(o,e)},Q=[],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]&&q(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),v.length>1&&(u?r.a.createElement(y,Object(n.a)({changeSelectedValue:k,handleKeydown:x,placeholder:s,selectedValue:N,size:h,tabRefs:Q},e)):r.a.createElement(m,Object(n.a)({changeSelectedValue:k,handleKeydown:x,selectedValue:N,tabRefs:Q},e)))),l.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},466: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/ac2c90fd.026d02fe.js b/ac2c90fd.7e3be788.js similarity index 96% rename from ac2c90fd.026d02fe.js rename to ac2c90fd.7e3be788.js index 037fe4f5db..165f25dc53 100644 --- a/ac2c90fd.026d02fe.js +++ b/ac2c90fd.7e3be788.js @@ -1,2 +1,2 @@ -/*! For license information please see ac2c90fd.026d02fe.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[190],{342: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(449)),s=n(448),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},447: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.7e3be788.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[192],{344: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(451)),s=n(450),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},449: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/b0059451.8c63ba07.js.LICENSE.txt b/ac2c90fd.7e3be788.js.LICENSE.txt similarity index 100% rename from b0059451.8c63ba07.js.LICENSE.txt rename to ac2c90fd.7e3be788.js.LICENSE.txt diff --git a/a4c8ecc0.806fac79.js b/acaf40e9.d9044bd7.js similarity index 95% rename from a4c8ecc0.806fac79.js rename to acaf40e9.d9044bd7.js index 168f95ff33..ced992d9a0 100644 --- a/a4c8ecc0.806fac79.js +++ b/acaf40e9.d9044bd7.js @@ -1,2 +1,2 @@ -/*! For license information please see a4c8ecc0.806fac79.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[181],{333: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(449)),i=(n(448),n(453),n(457),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(458),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}))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(454),i=n(447),l=n.n(i);n(134);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)}},458: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.d9044bd7.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[193],{345: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(451)),i=(n(450),n(455),n(459),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(460),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}))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(456),i=n(449),l=n.n(i);n(134);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)}},460: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/b2880863.4b38b481.js.LICENSE.txt b/acaf40e9.d9044bd7.js.LICENSE.txt similarity index 100% rename from b2880863.4b38b481.js.LICENSE.txt rename to acaf40e9.d9044bd7.js.LICENSE.txt diff --git a/accdb2b4.44db9f8e.js b/accdb2b4.0d9abc97.js similarity index 96% rename from accdb2b4.44db9f8e.js rename to accdb2b4.0d9abc97.js index d6801c0a8d..ad6c970f95 100644 --- a/accdb2b4.44db9f8e.js +++ b/accdb2b4.0d9abc97.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[192],{344: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(449)),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},449: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||(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):i({},t,{},e)),r},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(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),f=n,m=p["".concat(c,".").concat(f)]||p[f]||d[f]||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]=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:n,c[1]=i;for(var u=2;u0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):o.a.createElement("a",Object(n.a)({},e,{href:l}))}},457:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(454),c=r(447),i=r.n(c);r(134);t.a=function(e){var t=e.children,r=e.className,n=e.badge,c=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,d=i()("jump-to","jump-to--"+u,r),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"},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 l?a.a.createElement("a",{href:p,target:l,className:d},f):a.a.createElement(o.a,{to:p,className:d},f)}},458: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 b0059451.d66d2330.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[197],{348:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return s})),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(451)),c=r(459),i={last_modified_on:"2023-12-30",title:"Managed By Qovery",sidebar_label:"hidden",hide_pagination:!0},s={id:"getting-started/install-qovery/scaleway/cluster-managed-by-qovery",title:"Managed By Qovery",description:"import Jump from '@site/src/components/Jump';",source:"@site/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery.md",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Scaleway",permalink:"/docs/getting-started/install-qovery/scaleway"},next:{title:"Quickstart",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart"}},u=[],l={rightToc:u};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,"Don't be shy, pick the first page you want to read and start your journey with Qovery."),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart",mdxType:"Jump"},"Quickstart"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/create-credentials",mdxType:"Jump"},"Create Credentials"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/faq",mdxType:"Jump"},"FAQ"))}p.isMDXComponent=!0},449: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({}),l=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=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(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),f=n,m=p["".concat(c,".").concat(f)]||p[f]||d[f]||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]=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:n,c[1]=i;for(var u=2;u0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):o.a.createElement("a",Object(n.a)({},e,{href:l}))}},459:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(456),c=r(449),i=r.n(c);r(134);t.a=function(e){var t=e.children,r=e.className,n=e.badge,c=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,d=i()("jump-to","jump-to--"+u,r),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"},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 l?a.a.createElement("a",{href:p,target:l,className:d},f):a.a.createElement(o.a,{to:p,className:d},f)}},460: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/b479fc9a.9f8c87d7.js.LICENSE.txt b/b0059451.d66d2330.js.LICENSE.txt similarity index 100% rename from b479fc9a.9f8c87d7.js.LICENSE.txt rename to b0059451.d66d2330.js.LICENSE.txt diff --git a/b2880863.4b38b481.js b/b2880863.be9c6947.js similarity index 96% rename from b2880863.4b38b481.js rename to b2880863.be9c6947.js index 339d6c96aa..fa6871088e 100644 --- a/b2880863.4b38b481.js +++ b/b2880863.be9c6947.js @@ -1,2 +1,2 @@ -/*! For license information please see b2880863.4b38b481.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[196],{347: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(449)),c=n(448),i=(n(457),n(453),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),l=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),l=n.n(r),c=n(39),i=n(458),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}))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),l=n(454),c=n(447),i=n.n(c);n(134);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)}},458: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.be9c6947.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 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(451)),c=n(450),i=(n(459),n(455),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),l=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),l=n.n(r),c=n(39),i=n(460),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}))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),l=n(456),c=n(449),i=n.n(c);n(134);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)}},460: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.dfa8a95a.js.LICENSE.txt b/b2880863.be9c6947.js.LICENSE.txt similarity index 100% rename from b4dda200.dfa8a95a.js.LICENSE.txt rename to b2880863.be9c6947.js.LICENSE.txt diff --git a/b5eab6bb.40dc648f.js b/b479fc9a.ac7136dd.js similarity index 92% rename from b5eab6bb.40dc648f.js rename to b479fc9a.ac7136dd.js index 7a6c2c4083..3d2f3d4fcc 100644 --- a/b5eab6bb.40dc648f.js +++ b/b479fc9a.ac7136dd.js @@ -1,2 +1,2 @@ -/*! For license information please see b5eab6bb.40dc648f.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[203],{354: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 d}));var a=n(1),r=n(9),o=(n(0),n(449)),i=n(456),c=(n(448),n(453)),l=(n(457),{last_modified_on:"2024-04-10",$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/acarranoqovery",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:"Installation",id:"installation",children:[]},{value:"Conclusion",id:"conclusion",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)("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 a dedicated Qovery project and environment to deploy Datadog (example: Project=Tooling, Environment=Production)"),Object(o.b)("li",{parentName:"ul"},"You have a Datadog account"),Object(o.b)("li",{parentName:"ul"},"You have already created a ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://docs.datadoghq.com/account_management/api-app-keys/#api-keys"}),"Datadog API Key")))),Object(o.b)("h2",{id:"installation"},"Installation"),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:"add-the-datadog-helm-repository"},"Add the Datadog helm repository"),Object(o.b)("p",null,"Add the Datadog helm repository in your Qovery settings by following ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/helm-repository/"}),"this documentation")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Repository name: ",Object(o.b)("inlineCode",{parentName:"li"},"Datadog")),Object(o.b)("li",{parentName:"ul"},"Kind: ",Object(o.b)("inlineCode",{parentName:"li"},"HTTPS")),Object(o.b)("li",{parentName:"ul"},"Repository URL: ",Object(o.b)("inlineCode",{parentName:"li"},"https://helm.datadoghq.com")))),Object(o.b)("li",null,Object(o.b)("h4",{id:"create-the-datadog-service-within-qovery"},"Create the datadog service within Qovery"),Object(o.b)("p",null,"Create the Datadog helm service in the Qovery environment of your choice (preferrably within a dedicated Tooling project) by following ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/"}),"this documentation")," and these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"General:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Application name: ",Object(o.b)("inlineCode",{parentName:"li"},"Datadog")),Object(o.b)("li",{parentName:"ul"},"Source:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Helm source: ",Object(o.b)("inlineCode",{parentName:"li"},"Helm repository")),Object(o.b)("li",{parentName:"ul"},"Repository: ",Object(o.b)("inlineCode",{parentName:"li"},"Datadog")," (the name given during the datadog helm repository added in the previous step)"),Object(o.b)("li",{parentName:"ul"},"Chart name: ",Object(o.b)("inlineCode",{parentName:"li"},"datadog")),Object(o.b)("li",{parentName:"ul"},"Version: ",Object(o.b)("inlineCode",{parentName:"li"},"3.49.5")," (this is the version we used for this setup, update it based on the chosen version)"),Object(o.b)("li",{parentName:"ul"},"Allow cluster-wide resources \u2714\ufe0f"))))),Object(o.b)("li",{parentName:"ul"},"Values",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Values override as file:"),Object(o.b)("li",{parentName:"ul"},"File source: ",Object(o.b)("inlineCode",{parentName:"li"},"Raw YAML")),Object(o.b)("li",{parentName:"ul"},"Raw YAML:")))),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),"# The following YAML contains the minimum configuration required to deploy the Datadog Agent\n# on your cluster. Update it accordingly to your needs\ndatadog:\n # here we use a Qovery secret to retrieve the Datadog API Key (See next step)\n apiKey: qovery.env.DD_API_KEY\n # Update the site depending on where you want to store your data in Datadog\n site: datadoghq.eu\n # Update the cluster name with the name of your choice\n clusterName: qoverycluster\n")),Object(o.b)("p",null,"There are many other values you can set and modify the Datadog agent behaviour. 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)("p",null,"Now get to the last step and just ",Object(o.b)("inlineCode",{parentName:"p"},"Create")," the service on Qovery.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"store-the-datadog-api-key-as-secret"},"Store the Datadog API Key as secret"),Object(o.b)("p",null,"In the previous step we have assigned the macro ",Object(o.b)("inlineCode",{parentName:"p"},"qovery.env.DD_API_KEY")," to the API Key value. In this step we will create this secret within the Qovery console."),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Open the service overview of the created Datadog service"),Object(o.b)("li",{parentName:"ul"},"Enter the ",Object(o.b)("inlineCode",{parentName:"li"},"Variables")," section"),Object(o.b)("li",{parentName:"ul"},"Add a new Variable with:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Variable = DD_API_KEY"),Object(o.b)("li",{parentName:"ul"},"Value = "),Object(o.b)("li",{parentName:"ul"},"Scope = Service (so that it is accessible only to this service)"),Object(o.b)("li",{parentName:"ul"},"Secret variable \u2714\ufe0f")))),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/datadog-secret.png",alt:"Datadog - API Key"})),Object(o.b)("p",null,"If you need more information on how to manage your environment variables, have a look at ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"this documentation"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"deploy-your-chart"},"Deploy your chart"),Object(o.b)("p",null,"Open the ",Object(o.b)("inlineCode",{parentName:"p"},"Play")," button and trigger the deployment of your chart (see point 1 in the picture below)."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/deploy.png",alt:"Datadog - Deploy"})),Object(o.b)("p",null,"You can follow the deployment and access the deployment logs by pressing the ",Object(o.b)("inlineCode",{parentName:"p"},"Log")," button (see point 2 in the picutre above)."),Object(o.b)("p",null,"Once the deployment is completed, you should see the Datadog agent pods and their status directly within the Qovery console."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/datadog-pods.png",alt:"Datadog - Pods"})),Object(o.b)("p",null,"You can also look at the Pod logs by pressing the ",Object(o.b)("inlineCode",{parentName:"p"},"Log")," button.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"verify-the-setup-on-datadog"},"Verify the setup on Datadog"),Object(o.b)("p",null,"Access again your Datadog interface and access the Infrastructure > Containers > Kubernetes sections. You should now see the data coming from your Qovery cluster"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/datadog-console.png",alt:"Datadog - Console"}))))),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"),"."))}d.isMDXComponent=!0},447: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)},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,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(n),p=a,m=b["".concat(i,".").concat(p)]||b[p]||d[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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),c=n(458),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),d=Object(r.useRef)(!1),p=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!p&&b&&window.docusaurus.prefetch(u),function(){p&&t&&t.disconnect()}}),[u,p,b]),u&&b?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;p&&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}))}},455:function(e,t,n){"use strict";var a=n(459),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("&"):""}},456:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(447),n(455)),i=n.n(o);n(133);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),b=u[0],d=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 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"),"."))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(454),i=n(447),c=n.n(i);n(134);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,b=e.to,d=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:b,target:u,className:d},p):r.a.createElement(o.a,{to:b,className:d},p)}},458:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},459: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.ac7136dd.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[199],{350: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 d}));var a=n(1),r=n(9),o=(n(0),n(451)),i=n(458),c=(n(450),n(455)),l=(n(459),{last_modified_on:"2024-04-10",$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/acarranoqovery",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:"Installation",id:"installation",children:[]},{value:"Conclusion",id:"conclusion",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)("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 a dedicated Qovery project and environment to deploy Datadog (example: Project=Tooling, Environment=Production)"),Object(o.b)("li",{parentName:"ul"},"You have a Datadog account"),Object(o.b)("li",{parentName:"ul"},"You have already created a ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://docs.datadoghq.com/account_management/api-app-keys/#api-keys"}),"Datadog API Key")))),Object(o.b)("h2",{id:"installation"},"Installation"),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:"add-the-datadog-helm-repository"},"Add the Datadog helm repository"),Object(o.b)("p",null,"Add the Datadog helm repository in your Qovery settings by following ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/helm-repository/"}),"this documentation")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Repository name: ",Object(o.b)("inlineCode",{parentName:"li"},"Datadog")),Object(o.b)("li",{parentName:"ul"},"Kind: ",Object(o.b)("inlineCode",{parentName:"li"},"HTTPS")),Object(o.b)("li",{parentName:"ul"},"Repository URL: ",Object(o.b)("inlineCode",{parentName:"li"},"https://helm.datadoghq.com")))),Object(o.b)("li",null,Object(o.b)("h4",{id:"create-the-datadog-service-within-qovery"},"Create the datadog service within Qovery"),Object(o.b)("p",null,"Create the Datadog helm service in the Qovery environment of your choice (preferrably within a dedicated Tooling project) by following ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/"}),"this documentation")," and these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"General:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Application name: ",Object(o.b)("inlineCode",{parentName:"li"},"Datadog")),Object(o.b)("li",{parentName:"ul"},"Source:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Helm source: ",Object(o.b)("inlineCode",{parentName:"li"},"Helm repository")),Object(o.b)("li",{parentName:"ul"},"Repository: ",Object(o.b)("inlineCode",{parentName:"li"},"Datadog")," (the name given during the datadog helm repository added in the previous step)"),Object(o.b)("li",{parentName:"ul"},"Chart name: ",Object(o.b)("inlineCode",{parentName:"li"},"datadog")),Object(o.b)("li",{parentName:"ul"},"Version: ",Object(o.b)("inlineCode",{parentName:"li"},"3.49.5")," (this is the version we used for this setup, update it based on the chosen version)"),Object(o.b)("li",{parentName:"ul"},"Allow cluster-wide resources \u2714\ufe0f"))))),Object(o.b)("li",{parentName:"ul"},"Values",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Values override as file:"),Object(o.b)("li",{parentName:"ul"},"File source: ",Object(o.b)("inlineCode",{parentName:"li"},"Raw YAML")),Object(o.b)("li",{parentName:"ul"},"Raw YAML:")))),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),"# The following YAML contains the minimum configuration required to deploy the Datadog Agent\n# on your cluster. Update it accordingly to your needs\ndatadog:\n # here we use a Qovery secret to retrieve the Datadog API Key (See next step)\n apiKey: qovery.env.DD_API_KEY\n # Update the site depending on where you want to store your data in Datadog\n site: datadoghq.eu\n # Update the cluster name with the name of your choice\n clusterName: qoverycluster\n")),Object(o.b)("p",null,"There are many other values you can set and modify the Datadog agent behaviour. 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)("p",null,"Now get to the last step and just ",Object(o.b)("inlineCode",{parentName:"p"},"Create")," the service on Qovery.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"store-the-datadog-api-key-as-secret"},"Store the Datadog API Key as secret"),Object(o.b)("p",null,"In the previous step we have assigned the macro ",Object(o.b)("inlineCode",{parentName:"p"},"qovery.env.DD_API_KEY")," to the API Key value. In this step we will create this secret within the Qovery console."),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Open the service overview of the created Datadog service"),Object(o.b)("li",{parentName:"ul"},"Enter the ",Object(o.b)("inlineCode",{parentName:"li"},"Variables")," section"),Object(o.b)("li",{parentName:"ul"},"Add a new Variable with:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Variable = DD_API_KEY"),Object(o.b)("li",{parentName:"ul"},"Value = "),Object(o.b)("li",{parentName:"ul"},"Scope = Service (so that it is accessible only to this service)"),Object(o.b)("li",{parentName:"ul"},"Secret variable \u2714\ufe0f")))),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/datadog-secret.png",alt:"Datadog - API Key"})),Object(o.b)("p",null,"If you need more information on how to manage your environment variables, have a look at ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"this documentation"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"deploy-your-chart"},"Deploy your chart"),Object(o.b)("p",null,"Open the ",Object(o.b)("inlineCode",{parentName:"p"},"Play")," button and trigger the deployment of your chart (see point 1 in the picture below)."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/deploy.png",alt:"Datadog - Deploy"})),Object(o.b)("p",null,"You can follow the deployment and access the deployment logs by pressing the ",Object(o.b)("inlineCode",{parentName:"p"},"Log")," button (see point 2 in the picutre above)."),Object(o.b)("p",null,"Once the deployment is completed, you should see the Datadog agent pods and their status directly within the Qovery console."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/datadog-pods.png",alt:"Datadog - Pods"})),Object(o.b)("p",null,"You can also look at the Pod logs by pressing the ",Object(o.b)("inlineCode",{parentName:"p"},"Log")," button.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"verify-the-setup-on-datadog"},"Verify the setup on Datadog"),Object(o.b)("p",null,"Access again your Datadog interface and access the Infrastructure > Containers > Kubernetes sections. You should now see the data coming from your Qovery cluster"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/datadog-console.png",alt:"Datadog - Console"}))))),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"),"."))}d.isMDXComponent=!0},449: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)},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,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(n),p=a,m=b["".concat(i,".").concat(p)]||b[p]||d[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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),c=n(460),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),d=Object(r.useRef)(!1),p=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!p&&b&&window.docusaurus.prefetch(u),function(){p&&t&&t.disconnect()}}),[u,p,b]),u&&b?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;p&&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}))}},457:function(e,t,n){"use strict";var a=n(461),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("&"):""}},458:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(449),n(457)),i=n.n(o);n(133);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),b=u[0],d=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 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"),"."))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(456),i=n(449),c=n.n(i);n(134);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,b=e.to,d=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:b,target:u,className:d},p):r.a.createElement(o.a,{to:b,className:d},p)}},460:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},461: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/b538f6fb.427c650a.js.LICENSE.txt b/b479fc9a.ac7136dd.js.LICENSE.txt similarity index 100% rename from b538f6fb.427c650a.js.LICENSE.txt rename to b479fc9a.ac7136dd.js.LICENSE.txt diff --git a/b49a87dd.78db5f66.js b/b49a87dd.8935c416.js similarity index 96% rename from b49a87dd.78db5f66.js rename to b49a87dd.8935c416.js index aaf8336244..1d4177b5d5 100644 --- a/b49a87dd.78db5f66.js +++ b/b49a87dd.8935c416.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[198],{349:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return u})),a.d(t,"metadata",(function(){return p})),a.d(t,"rightToc",(function(){return d})),a.d(t,"default",(function(){return h}));var n,l=a(1),r=a(9),o=(a(0),a(449)),c=a(464),s=a(456),b=a(448),i=a(461),u={last_modified_on:"2024-07-12",title:"Self-Managed Cluster",description:"Learn how to install and configure Qovery on your GCP Kubernetes Service (GKE) cluster"},p={id:"getting-started/install-qovery/gcp/self-managed-cluster",title:"Self-Managed Cluster",description:"Learn how to install and configure Qovery on your GCP Kubernetes Service (GKE) cluster",source:"@site/docs/getting-started/install-qovery/gcp/self-managed-cluster.md",permalink:"/docs/getting-started/install-qovery/gcp/self-managed-cluster",sidebar:"docs",previous:{title:"Create Credentials",permalink:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials"},next:{title:"Scaleway",permalink:"/docs/getting-started/install-qovery/scaleway"}},d=[{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Install Qovery on your GCP GKE cluster",id:"install-qovery-on-your-gcp-gke-cluster",children:[]},{value:"What's Next?",id:"whats-next",children:[]}],m=(n="Assumption",function(e){return console.warn("Component "+n+" was not imported, exported, or provided by MDXProvider as global scope"),Object(o.b)("div",e)}),y={rightToc:d};function h(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(l.a)({},y,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are not familiar with Kubernetes, we recommend you to use Qovery on a Managed Kubernetes cluster on ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/"}),"AWS"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/"}),"GCP"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/"}),"Scaleway"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart/"}),"Azure"),", or contact us.")),Object(o.b)("p",null,"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.\nRead ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/blog/kubernetes-managed-by-qovery-vs-self-managed-byok"}),"this article")," to better understand the difference with the Managed Kubernetes by Qovery. In a nutshell, Qovery 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."),Object(o.b)(b.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery automatically updates ",Object(o.b)("strong",{parentName:"p"},"ONLY")," the Qovery applications (agent, shell-agent etc..) via the Qovery Helm chart. With the self-managed offer it will be up to you to manage any dependency components (ingress, dns, logging...), making sure they run with the right version over time."),Object(o.b)("p",null,"The dependencies provided with the Qovery Helm chart are here to help you with the bootstrap, and are not maintained by Qovery. If you want to simplify the maintenance of your cluster, please look at ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/pricing/"}),"Qovery managed Kubernetes offer"),".")),Object(o.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(o.b)(m,{mdxType:"Assumption"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a GCP GKE Kubernetes cluster up and running."),Object(o.b)("li",{parentName:"ul"},"You have a GCP GKE Kubernetes cluster with at least 4 CPUs and 8GB of RAM."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"kubectl")," installed and configured to access your GCP GKE Kubernetes cluster."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"helm")," installed."),Object(o.b)("li",{parentName:"ul"},"You have a Qovery account. If you don't have one, please sign up at ",Object(o.b)("a",Object(l.a)({parentName:"li"},{href:"https://start.qovery.com"}),"https://start.qovery.com")))),Object(o.b)("h2",{id:"install-qovery-on-your-gcp-gke-cluster"},"Install Qovery on your GCP GKE cluster"),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/local/"}),"this guide")," to try Qovery on your local machine.")),Object(o.b)(i.a,{centered:!0,className:"rounded",defaultValue:"automatic",placeholder:"Install Qovery",select:!1,size:null,values:[{group:"Install",label:"Automatic",value:"automatic"},{group:"Install",label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.a,{value:"automatic",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery CLI by running the following command:"),Object(o.b)(i.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)(c.a,{value:"linux",mdxType:"TabItem"},Object(o.b)(i.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.a,{value:"arch",mdxType:"TabItem"},Object(o.b)("p",null,"Qovery is part of ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"macos",mdxType:"TabItem"},Object(o.b)(i.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)(c.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(l.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"windows",mdxType:"TabItem"},Object(o.b)(i.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.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(l.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.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)(c.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(l.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(l.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(l.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)("p",null,"Authenticate with Qovery by running the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are using a headless (without GUI) environment, you can use the following command to sign up and sign in:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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 Qovery sign-up page will open. Follow the instructions to sign up and sign in.")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your GCP GKE cluster:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"qovery cluster install\n")),Object(o.b)("p",null,"Respond to the prompts to install Qovery on your GCP GKE Kubernetes cluster."))))),Object(o.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://helm.sh"}),"Helm")," command line tool.")),Object(o.b)("li",null,Object(o.b)("p",null,"Add Qovery Helm repository."),Object(o.b)(b.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery Helm Chart is only available for users who have access to Qovery BYOK. ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/bring-your-own-kubernetes"}),"Request your access here"),".")),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm repo add qovery https://helm.qovery.com\nhelm repo update\n"))),Object(o.b)("li",null,Object(o.b)("p",null,"Login to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console"),", create a cluster of type ",Object(o.b)("inlineCode",{parentName:"p"},"Self-Managed"),". At the end of the flow you will be able to download the ",Object(o.b)("inlineCode",{parentName:"p"},"values.yaml")," file associated with this cluster.")),Object(o.b)("li",null,Object(o.b)("p",null,"Now you can customize your values.yaml file based on your need. Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),"."),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Make sure that all fields having value ",Object(o.b)("inlineCode",{parentName:"p"},"set-by-customer")," are filled.")),Object(o.b)("p",null,"Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your Kubernetes cluster."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --wait --atomic --create-namespace -n qovery -f \\\n --set services.certificates.cert-manager-configs.enabled=false \\\n --set services.certificates.qovery-cert-manager-webhook.enabled=false \\\n --set services.qovery.qovery-cluster-agent.enabled=false \\\n --set services.qovery.qovery-engine.enabled=false \\\n qovery qovery/qovery\n")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-n qovery"),": the namespace where Qovery and its dependencies will be installed"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"--set..."),": override (only for the first deployment time, if you want to use Cert-Manager) to let cert-manager install its CRDs"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-f your-values-file.yaml"),": the values file you've downloaded, overrided with the Qovery config and your custom config"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery/qovery"),": name of the chart to deploy"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery"),": name of the release")),Object(o.b)("p",null,"If you want to use Cert-Manager, you can remove the ",Object(o.b)("inlineCode",{parentName:"p"},"--set...")," for the future updates (or if already installed):"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --create-namespace -n qovery -f --wait --atomic qovery qovery/qovery\n"))))))),Object(o.b)("p",null,"That's it, you can now use Qovery on your GCP GKE cluster."),Object(o.b)("p",null,"Connect to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console")," to validate that Qovery is properly installed and start deploying your applications."),Object(o.b)("h2",{id:"whats-next"},"What's Next?"),Object(o.b)("p",null,"Now that you have Qovery installed on your Kubernetes cluster, you can check that Qovery is properly installed by following the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/validate-installation/"}),"Validate Installation")," guide."))}h.isMDXComponent=!0},448:function(e,t,a){"use strict";a(450);var n=a(0),l=a.n(n),r=a(447),o=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,s=null;switch(c){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return l.a.createElement("div",{className:o()(a,"alert","alert--"+c,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&l.a.createElement("i",{className:o()("feather","icon-"+(r||s))}),t)}},456:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=(a(447),a(455)),o=a.n(r);a(133);t.a=function(e){var t=e.children,a=e.headingDepth,r=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"},b="https://github.com/qovery/documentation/issues/new?"+o.a.stringify(s),i=Object(n.useState)(null),u=i[0],p=i[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:b,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"),"."))}},461:function(e,t,a){"use strict";var n=a(1),l=(a(465),a(462),a(52),a(29),a(22),a(21),a(0)),r=a.n(l),o=a(469),c=a(447),s=a.n(c),b=a(455),i=a.n(b),u=a(468),p=37,d=39;function m(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,l=e.className,o=e.handleKeydown,c=e.style,b=e.values,i=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:s()("tabs",l,{"tabs--block":t}),style:c},b.map((function(e){var t=e.value,a=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":i===t,className:s()("tab-item",{"tab-item--active":i===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return o(u,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function y(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,l=e.size,c=e.values,s=c;if(s[0].group){var b=_.groupBy(s,"group");s=Object.keys(b).map((function(e){return{label:e,options:b[e]}}))}return r.a.createElement(o.a,{className:"react-select-container react-select--"+l,classNamePrefix:"react-select",options:s,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,o=e.groupId,c=e.label,s=e.placeholder,b=e.select,h=e.size,v=(e.style,e.values),O=e.urlKey,g=Object(u.a)(),j=g.tabGroupChoices,f=g.setTabGroupChoices,w=Object(l.useState)(a),N=w[0],q=w[1];if(null!=o){var T=j[o];null!=T&&T!==N&&q(T)}var C=function(e){q(e),null!=o&&f(o,e)},k=[],Q=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=i.a.parse(window.location.search);e[O]&&q(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),v.length>1&&(b?r.a.createElement(y,Object(n.a)({changeSelectedValue:C,handleKeydown:Q,placeholder:s,selectedValue:N,size:h,tabRefs:k},e)):r.a.createElement(m,Object(n.a)({changeSelectedValue:C,handleKeydown:Q,selectedValue:N,tabRefs:k},e)))),l.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},464: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([[200],{351:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return u})),a.d(t,"metadata",(function(){return p})),a.d(t,"rightToc",(function(){return d})),a.d(t,"default",(function(){return h}));var n,l=a(1),r=a(9),o=(a(0),a(451)),c=a(466),s=a(458),b=a(450),i=a(463),u={last_modified_on:"2024-07-12",title:"Self-Managed Cluster",description:"Learn how to install and configure Qovery on your GCP Kubernetes Service (GKE) cluster"},p={id:"getting-started/install-qovery/gcp/self-managed-cluster",title:"Self-Managed Cluster",description:"Learn how to install and configure Qovery on your GCP Kubernetes Service (GKE) cluster",source:"@site/docs/getting-started/install-qovery/gcp/self-managed-cluster.md",permalink:"/docs/getting-started/install-qovery/gcp/self-managed-cluster",sidebar:"docs",previous:{title:"Create Credentials",permalink:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials"},next:{title:"Scaleway",permalink:"/docs/getting-started/install-qovery/scaleway"}},d=[{value:"Prerequisites",id:"prerequisites",children:[]},{value:"Install Qovery on your GCP GKE cluster",id:"install-qovery-on-your-gcp-gke-cluster",children:[]},{value:"What's Next?",id:"whats-next",children:[]}],m=(n="Assumption",function(e){return console.warn("Component "+n+" was not imported, exported, or provided by MDXProvider as global scope"),Object(o.b)("div",e)}),y={rightToc:d};function h(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(l.a)({},y,a,{components:t,mdxType:"MDXLayout"}),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are not familiar with Kubernetes, we recommend you to use Qovery on a Managed Kubernetes cluster on ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/"}),"AWS"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/"}),"GCP"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/"}),"Scaleway"),", ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart/"}),"Azure"),", or contact us.")),Object(o.b)("p",null,"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.\nRead ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/blog/kubernetes-managed-by-qovery-vs-self-managed-byok"}),"this article")," to better understand the difference with the Managed Kubernetes by Qovery. In a nutshell, Qovery 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."),Object(o.b)(b.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery automatically updates ",Object(o.b)("strong",{parentName:"p"},"ONLY")," the Qovery applications (agent, shell-agent etc..) via the Qovery Helm chart. With the self-managed offer it will be up to you to manage any dependency components (ingress, dns, logging...), making sure they run with the right version over time."),Object(o.b)("p",null,"The dependencies provided with the Qovery Helm chart are here to help you with the bootstrap, and are not maintained by Qovery. If you want to simplify the maintenance of your cluster, please look at ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/pricing/"}),"Qovery managed Kubernetes offer"),".")),Object(o.b)("h2",{id:"prerequisites"},"Prerequisites"),Object(o.b)(m,{mdxType:"Assumption"},Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"You have a GCP GKE Kubernetes cluster up and running."),Object(o.b)("li",{parentName:"ul"},"You have a GCP GKE Kubernetes cluster with at least 4 CPUs and 8GB of RAM."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"kubectl")," installed and configured to access your GCP GKE Kubernetes cluster."),Object(o.b)("li",{parentName:"ul"},"You have ",Object(o.b)("inlineCode",{parentName:"li"},"helm")," installed."),Object(o.b)("li",{parentName:"ul"},"You have a Qovery account. If you don't have one, please sign up at ",Object(o.b)("a",Object(l.a)({parentName:"li"},{href:"https://start.qovery.com"}),"https://start.qovery.com")))),Object(o.b)("h2",{id:"install-qovery-on-your-gcp-gke-cluster"},"Install Qovery on your GCP GKE cluster"),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Follow ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/local/"}),"this guide")," to try Qovery on your local machine.")),Object(o.b)(i.a,{centered:!0,className:"rounded",defaultValue:"automatic",placeholder:"Install Qovery",select:!1,size:null,values:[{group:"Install",label:"Automatic",value:"automatic"},{group:"Install",label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.a,{value:"automatic",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery CLI by running the following command:"),Object(o.b)(i.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)(c.a,{value:"linux",mdxType:"TabItem"},Object(o.b)(i.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.a,{value:"arch",mdxType:"TabItem"},Object(o.b)("p",null,"Qovery is part of ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"$ yay qovery-cli\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"macos",mdxType:"TabItem"},Object(o.b)(i.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)(c.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(l.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.a)({parentName:"pre"},{className:"language-bash"}),"$ curl -s https://get.qovery.com | bash\n"))),Object(o.b)(c.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(l.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)(c.a,{value:"windows",mdxType:"TabItem"},Object(o.b)(i.a,{centered:!0,className:"rounded",defaultValue:"scoop",values:[{label:"Scoop",value:"scoop"},{label:"Manual",value:"manual"}],mdxType:"Tabs"},Object(o.b)(c.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(l.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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)(c.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(l.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)(c.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(l.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(l.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(l.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)("p",null,"Authenticate with Qovery by running the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you are using a headless (without GUI) environment, you can use the following command to sign up and sign in:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.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 Qovery sign-up page will open. Follow the instructions to sign up and sign in.")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your GCP GKE cluster:"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"qovery cluster install\n")),Object(o.b)("p",null,"Respond to the prompts to install Qovery on your GCP GKE Kubernetes cluster."))))),Object(o.b)(c.a,{value:"manual",mdxType:"TabItem"},Object(o.b)(s.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("p",null,"Install ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://helm.sh"}),"Helm")," command line tool.")),Object(o.b)("li",null,Object(o.b)("p",null,"Add Qovery Helm repository."),Object(o.b)(b.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Qovery Helm Chart is only available for users who have access to Qovery BYOK. ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://www.qovery.com/solutions/bring-your-own-kubernetes"}),"Request your access here"),".")),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm repo add qovery https://helm.qovery.com\nhelm repo update\n"))),Object(o.b)("li",null,Object(o.b)("p",null,"Login to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console"),", create a cluster of type ",Object(o.b)("inlineCode",{parentName:"p"},"Self-Managed"),". At the end of the flow you will be able to download the ",Object(o.b)("inlineCode",{parentName:"p"},"values.yaml")," file associated with this cluster.")),Object(o.b)("li",null,Object(o.b)("p",null,"Now you can customize your values.yaml file based on your need. Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),"."),Object(o.b)(b.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Make sure that all fields having value ",Object(o.b)("inlineCode",{parentName:"p"},"set-by-customer")," are filled.")),Object(o.b)("p",null,"Learn more about the configuration in the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/byok-config/"}),"Configuration page"),".")),Object(o.b)("li",null,Object(o.b)("p",null,"Install Qovery on your Kubernetes cluster."),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --wait --atomic --create-namespace -n qovery -f \\\n --set services.certificates.cert-manager-configs.enabled=false \\\n --set services.certificates.qovery-cert-manager-webhook.enabled=false \\\n --set services.qovery.qovery-cluster-agent.enabled=false \\\n --set services.qovery.qovery-engine.enabled=false \\\n qovery qovery/qovery\n")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-n qovery"),": the namespace where Qovery and its dependencies will be installed"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"--set..."),": override (only for the first deployment time, if you want to use Cert-Manager) to let cert-manager install its CRDs"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"-f your-values-file.yaml"),": the values file you've downloaded, overrided with the Qovery config and your custom config"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery/qovery"),": name of the chart to deploy"),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"qovery"),": name of the release")),Object(o.b)("p",null,"If you want to use Cert-Manager, you can remove the ",Object(o.b)("inlineCode",{parentName:"p"},"--set...")," for the future updates (or if already installed):"),Object(o.b)("pre",null,Object(o.b)("code",Object(l.a)({parentName:"pre"},{className:"language-bash"}),"helm upgrade --install --create-namespace -n qovery -f --wait --atomic qovery qovery/qovery\n"))))))),Object(o.b)("p",null,"That's it, you can now use Qovery on your GCP GKE cluster."),Object(o.b)("p",null,"Connect to the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console")," to validate that Qovery is properly installed and start deploying your applications."),Object(o.b)("h2",{id:"whats-next"},"What's Next?"),Object(o.b)("p",null,"Now that you have Qovery installed on your Kubernetes cluster, you can check that Qovery is properly installed by following the ",Object(o.b)("a",Object(l.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/validate-installation/"}),"Validate Installation")," guide."))}h.isMDXComponent=!0},450:function(e,t,a){"use strict";a(452);var n=a(0),l=a.n(n),r=a(449),o=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,s=null;switch(c){case"danger":s="alert-triangle";break;case"success":s="check-circle";break;case"warning":s="alert-triangle";break;default:s="info"}return l.a.createElement("div",{className:o()(a,"alert","alert--"+c,{"alert--fill":n,"alert--icon":!1!==r}),role:"alert"},!1!==r&&l.a.createElement("i",{className:o()("feather","icon-"+(r||s))}),t)}},458:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=(a(449),a(457)),o=a.n(r);a(133);t.a=function(e){var t=e.children,a=e.headingDepth,r=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"},b="https://github.com/qovery/documentation/issues/new?"+o.a.stringify(s),i=Object(n.useState)(null),u=i[0],p=i[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:b,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"),"."))}},463:function(e,t,a){"use strict";var n=a(1),l=(a(467),a(464),a(52),a(29),a(22),a(21),a(0)),r=a.n(l),o=a(471),c=a(449),s=a.n(c),b=a(457),i=a.n(b),u=a(470),p=37,d=39;function m(e){var t=e.block,a=e.centered,n=e.changeSelectedValue,l=e.className,o=e.handleKeydown,c=e.style,b=e.values,i=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:s()("tabs",l,{"tabs--block":t}),style:c},b.map((function(e){var t=e.value,a=e.label;return r.a.createElement("li",{role:"tab",tabIndex:"0","aria-selected":i===t,className:s()("tab-item",{"tab-item--active":i===t}),key:t,ref:function(e){return u.push(e)},onKeyDown:function(e){return o(u,e.target,e)},onFocus:function(){return n(t)},onClick:function(){return n(t)}},a)}))))}function y(e){var t=e.placeholder,a=e.selectedValue,n=e.changeSelectedValue,l=e.size,c=e.values,s=c;if(s[0].group){var b=_.groupBy(s,"group");s=Object.keys(b).map((function(e){return{label:e,options:b[e]}}))}return r.a.createElement(o.a,{className:"react-select-container react-select--"+l,classNamePrefix:"react-select",options:s,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,o=e.groupId,c=e.label,s=e.placeholder,b=e.select,h=e.size,v=(e.style,e.values),O=e.urlKey,g=Object(u.a)(),j=g.tabGroupChoices,f=g.setTabGroupChoices,w=Object(l.useState)(a),N=w[0],q=w[1];if(null!=o){var T=j[o];null!=T&&T!==N&&q(T)}var C=function(e){q(e),null!=o&&f(o,e)},k=[],Q=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=i.a.parse(window.location.search);e[O]&&q(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),v.length>1&&(b?r.a.createElement(y,Object(n.a)({changeSelectedValue:C,handleKeydown:Q,placeholder:s,selectedValue:N,size:h,tabRefs:k},e)):r.a.createElement(m,Object(n.a)({changeSelectedValue:C,handleKeydown:Q,selectedValue:N,tabRefs:k},e)))),l.Children.toArray(t).filter((function(e){return e.props.value===N}))[0])}},466: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/b4dda200.dfa8a95a.js b/b4dda200.cd36d0f8.js similarity index 88% rename from b4dda200.dfa8a95a.js rename to b4dda200.cd36d0f8.js index 9f05abca27..a524347aee 100644 --- a/b4dda200.dfa8a95a.js +++ b/b4dda200.cd36d0f8.js @@ -1,2 +1,2 @@ -/*! For license information please see b4dda200.dfa8a95a.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 u})),r.d(t,"metadata",(function(){return s})),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(449)),i=r(448),c=r(457),u={last_modified_on:"2023-12-26",title:"Troubleshoot",description:"Everything you need to troubleshoot your application with Qovery",sidebar_label:"hidden",hide_pagination:!0},s={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:"Service Deployment Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/service-deployment-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 your issue:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Service Deployment troubleshoot: you will find here the most common deployment errors and their solutions. "),Object(a.b)("li",{parentName:"ul"},"Service Run troubleshoot: you will find here the most common run errors and their solutions."),Object(a.b)("li",{parentName:"ul"},"Cluster troubleshoot: you will find here the error you might find while deploying or updating a cluster.")),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/service-deployment-troubleshoot/",mdxType:"Jump"},"Service deployment troubleshoot"),Object(a.b)(c.a,{to:"/docs/using-qovery/troubleshoot/service-run-troubleshoot/",mdxType:"Jump"},"Service run troubleshoot"))}f.isMDXComponent=!0},447: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)},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,s=u(e,["components","mdxType","originalType","parentName"]),p=l(r),d=n,m=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return r?o.a.createElement(m,c({ref:t},s,{components:r})):o.a.createElement(m,c({ref:t},s))}));function m(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 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:o(u,r);s>c;)t[c++]=e;return t}},454:function(e,t,r){"use strict";var n=r(1),o=r(0),a=r.n(o),i=r(39),c=r(458),u=r(20),s=r.n(u);t.a=function(e){var t,r=e.to,u=e.href,l=r||u,p=Object(c.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&&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}))}},457:function(e,t,r){"use strict";var n=r(0),o=r.n(n),a=r(454),i=r(447),c=r.n(i);r(134);t.a=function(e){var t=e.children,r=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,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-"+(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)}},458: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.cd36d0f8.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[201],{352:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return u})),r.d(t,"metadata",(function(){return s})),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(451)),i=r(450),c=r(459),u={last_modified_on:"2023-12-26",title:"Troubleshoot",description:"Everything you need to troubleshoot your application with Qovery",sidebar_label:"hidden",hide_pagination:!0},s={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:"Service Deployment Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/service-deployment-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 your issue:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Service Deployment troubleshoot: you will find here the most common deployment errors and their solutions. "),Object(a.b)("li",{parentName:"ul"},"Service Run troubleshoot: you will find here the most common run errors and their solutions."),Object(a.b)("li",{parentName:"ul"},"Cluster troubleshoot: you will find here the error you might find while deploying or updating a cluster.")),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/service-deployment-troubleshoot/",mdxType:"Jump"},"Service deployment troubleshoot"),Object(a.b)(c.a,{to:"/docs/using-qovery/troubleshoot/service-run-troubleshoot/",mdxType:"Jump"},"Service run troubleshoot"))}f.isMDXComponent=!0},449: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)},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,s=u(e,["components","mdxType","originalType","parentName"]),p=l(r),d=n,m=p["".concat(i,".").concat(d)]||p[d]||f[d]||a;return r?o.a.createElement(m,c({ref:t},s,{components:r})):o.a.createElement(m,c({ref:t},s))}));function m(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 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:o(u,r);s>c;)t[c++]=e;return t}},456:function(e,t,r){"use strict";var n=r(1),o=r(0),a=r.n(o),i=r(39),c=r(460),u=r(20),s=r.n(u);t.a=function(e){var t,r=e.to,u=e.href,l=r||u,p=Object(c.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&&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}))}},459:function(e,t,r){"use strict";var n=r(0),o=r.n(n),a=r(456),i=r(449),c=r.n(i);r(134);t.a=function(e){var t=e.children,r=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,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-"+(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)}},460: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/b5eab6bb.40dc648f.js.LICENSE.txt b/b4dda200.cd36d0f8.js.LICENSE.txt similarity index 100% rename from b5eab6bb.40dc648f.js.LICENSE.txt rename to b4dda200.cd36d0f8.js.LICENSE.txt diff --git a/b538f6fb.427c650a.js b/b538f6fb.94347130.js similarity index 92% rename from b538f6fb.427c650a.js rename to b538f6fb.94347130.js index c3550f6b23..81dc7ac187 100644 --- a/b538f6fb.427c650a.js +++ b/b538f6fb.94347130.js @@ -1,2 +1,2 @@ -/*! For license information please see b538f6fb.427c650a.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 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),o=n(9),a=(n(0),n(449)),i=n(448),c=n(456),l={last_modified_on:"2023-12-26",title:"Service Run Troubleshoot",description:"How to troubleshoot your service while it runs with Qovery",hide_pagination:!0},s={id:"using-qovery/troubleshoot/service-run-troubleshoot",title:"Service Run Troubleshoot",description:"How to troubleshoot your service while it runs with Qovery",source:"@site/docs/using-qovery/troubleshoot/service-run-troubleshoot.md",permalink:"/docs/using-qovery/troubleshoot/service-run-troubleshoot",sidebar:"docs",previous:{title:"Service Deployment Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/service-deployment-troubleshoot"},next:{title:"Cluster Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/cluster-troubleshoot"}},u=[{value:"My app is crashing, how do I connect to investigate?",id:"my-app-is-crashing-how-do-i-connect-to-investigate",children:[]},{value:"I can't access my application logs",id:"i-cant-access-my-application-logs",children:[]}],p={rightToc:u};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,"Within this section you will find the common errors you might encounter when running your services with Qovery"),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(r.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(r.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(r.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(r.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:"i-cant-access-my-application-logs"},"I can't access my application logs"),Object(a.b)("p",null,"If you are deploying a helm service, to get all the Qovery features (access your container logs, apply the stop/restart actions, display the pod status in the overview page), make sure to create an override and assign the macros ",Object(a.b)("inlineCode",{parentName:"p"},"qovery.labels.service")," and ",Object(a.b)("inlineCode",{parentName:"p"},"qovery.annotations.service")," to the labels and annotations of any deployed Pods/Deployments/Services/Jobs."),Object(a.b)("p",null,"Override example:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-yaml"}),'commonLabels:\n mylabel: "test"\n qovery.labels.service\nannotations:\n qovery.annotations.service\n')),Object(a.b)("p",null,"These macros will be automatically replaced by Qovery during the deployment phase."))}b.isMDXComponent=!0},447: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({}),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(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),d=r,y=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;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 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 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}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(447),n(455)),i=n.n(a);n(133);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(r.useState)(null),p=u[0],b=u[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: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"),"."))}},459: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 b538f6fb.94347130.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[202],{353: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),o=n(9),a=(n(0),n(451)),i=n(450),c=n(458),l={last_modified_on:"2023-12-26",title:"Service Run Troubleshoot",description:"How to troubleshoot your service while it runs with Qovery",hide_pagination:!0},s={id:"using-qovery/troubleshoot/service-run-troubleshoot",title:"Service Run Troubleshoot",description:"How to troubleshoot your service while it runs with Qovery",source:"@site/docs/using-qovery/troubleshoot/service-run-troubleshoot.md",permalink:"/docs/using-qovery/troubleshoot/service-run-troubleshoot",sidebar:"docs",previous:{title:"Service Deployment Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/service-deployment-troubleshoot"},next:{title:"Cluster Troubleshoot",permalink:"/docs/using-qovery/troubleshoot/cluster-troubleshoot"}},u=[{value:"My app is crashing, how do I connect to investigate?",id:"my-app-is-crashing-how-do-i-connect-to-investigate",children:[]},{value:"I can't access my application logs",id:"i-cant-access-my-application-logs",children:[]}],p={rightToc:u};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,"Within this section you will find the common errors you might encounter when running your services with Qovery"),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(r.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(r.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(r.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(r.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:"i-cant-access-my-application-logs"},"I can't access my application logs"),Object(a.b)("p",null,"If you are deploying a helm service, to get all the Qovery features (access your container logs, apply the stop/restart actions, display the pod status in the overview page), make sure to create an override and assign the macros ",Object(a.b)("inlineCode",{parentName:"p"},"qovery.labels.service")," and ",Object(a.b)("inlineCode",{parentName:"p"},"qovery.annotations.service")," to the labels and annotations of any deployed Pods/Deployments/Services/Jobs."),Object(a.b)("p",null,"Override example:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-yaml"}),'commonLabels:\n mylabel: "test"\n qovery.labels.service\nannotations:\n qovery.annotations.service\n')),Object(a.b)("p",null,"These macros will be automatically replaced by Qovery during the deployment phase."))}b.isMDXComponent=!0},449: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({}),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(r.forwardRef)((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(n),d=r,y=p["".concat(i,".").concat(d)]||p[d]||b[d]||a;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 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 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}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(449),n(457)),i=n.n(a);n(133);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(r.useState)(null),p=u[0],b=u[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: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"),"."))}},461: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/b7280cb5.7c939296.js.LICENSE.txt b/b538f6fb.94347130.js.LICENSE.txt similarity index 100% rename from b7280cb5.7c939296.js.LICENSE.txt rename to b538f6fb.94347130.js.LICENSE.txt diff --git a/b557ef1e.10842ee3.js b/b557ef1e.927d583d.js similarity index 97% rename from b557ef1e.10842ee3.js rename to b557ef1e.927d583d.js index d2c3cf66d4..0f627feb83 100644 --- a/b557ef1e.10842ee3.js +++ b/b557ef1e.927d583d.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[201],{352: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 s})),r.d(t,"default",(function(){return l}));var a=r(1),n=r(9),o=(r(0),r(449)),c={last_modified_on:"2024-04-12",title:"FAQ",description:"Frequently asked questions Scaleway infrastructure managed by Qovery"},i={id:"getting-started/install-qovery/scaleway/cluster-managed-by-qovery/faq",title:"FAQ",description:"Frequently asked questions Scaleway infrastructure managed by Qovery",source:"@site/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/faq.md",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/faq",sidebar:"docs",previous:{title:"Create Credentials",permalink:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/create-credentials"},next:{title:"Self-Managed Cluster",permalink:"/docs/getting-started/install-qovery/scaleway/self-managed-cluster"}},s=[{value:"How Qovery works on Managed Scaleway cluster",id:"how-qovery-works-on-managed-scaleway-cluster",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:[]}]}],u={rightToc:s};function l(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)("h2",{id:"how-qovery-works-on-managed-scaleway-cluster"},"How Qovery works on Managed Scaleway cluster"),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/roadmap"}),"here")," if you need this feature."))}l.isMDXComponent=!0},449:function(e,t,r){"use strict";r.d(t,"a",(function(){return d})),r.d(t,"b",(function(){return b}));var a=r(0),n=r.n(a);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 a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function i(e){for(var t=1;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 u=n.a.createContext({}),l=function(e){var t=n.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},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)}},y=Object(a.forwardRef)((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=l(r),y=a,b=d["".concat(c,".").concat(y)]||d[y]||p[y]||o;return r?n.a.createElement(b,i({ref:t},u,{components:r})):n.a.createElement(b,i({ref:t},u))}));function b(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,c=new Array(o);c[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:a,c[1]=i;for(var u=2;u=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 u=n.a.createContext({}),l=function(e){var t=n.a.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i({},t,{},e)),r},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)}},y=Object(a.forwardRef)((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=l(r),y=a,b=d["".concat(c,".").concat(y)]||d[y]||p[y]||o;return r?n.a.createElement(b,i({ref:t},u,{components:r})):n.a.createElement(b,i({ref:t},u))}));function b(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,c=new Array(o);c[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:a,c[1]=i;for(var u=2;u"]\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://console.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.png",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 a headless (without GUI) environment, you can use the following command to sign up and sign in:"),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 Qovery sign-up page will open. Follow the instructions to sign up and sign 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},448:function(e,t,a){"use strict";a(450);var n=a(0),r=a.n(n),o=a(447),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)}},452: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""}}})},453:function(e,t,a){"use strict";a(452);var n=a(0),r=a.n(n),o=a(448);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)}},454:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),l=a(39),i=a(458),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}))}},457:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(454),l=a(447),i=a.n(l);a(134);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)}},458:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},461:function(e,t,a){"use strict";var n=a(1),r=(a(465),a(462),a(52),a(29),a(22),a(21),a(0)),o=a.n(r),l=a(469),i=a(447),c=a.n(i),s=a(455),u=a.n(s),b=a(468),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,f=Object(b.a)(),y=f.tabGroupChoices,v=f.setTabGroupChoices,w=Object(r.useState)(a),N=w[0],R=w[1];if(null!=l){var T=y[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])}},464: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([[204],{355: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(451)),l=a(463),i=a(466),c=a(450),s=a(455),u=a(459),b={last_modified_on:"2024-05-03",$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 integrate Qovery with GitHub Actions",permalink:"/guides/tutorial/how-to-integrate-qovery-with-github-actions"}},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://console.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.png",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 a headless (without GUI) environment, you can use the following command to sign up and sign in:"),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 Qovery sign-up page will open. Follow the instructions to sign up and sign 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},450:function(e,t,a){"use strict";a(452);var n=a(0),r=a.n(n),o=a(449),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)}},454: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""}}})},455:function(e,t,a){"use strict";a(454);var n=a(0),r=a.n(n),o=a(450);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)}},456:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),l=a(39),i=a(460),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}))}},459:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(456),l=a(449),i=a.n(l);a(134);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)}},460:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},463:function(e,t,a){"use strict";var n=a(1),r=(a(467),a(464),a(52),a(29),a(22),a(21),a(0)),o=a.n(r),l=a(471),i=a(449),c=a.n(i),s=a(457),u=a.n(s),b=a(470),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,f=Object(b.a)(),y=f.tabGroupChoices,v=f.setTabGroupChoices,w=Object(r.useState)(a),N=w[0],R=w[1];if(null!=l){var T=y[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])}},466: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.9f8c87d7.js b/b5eab6bb.93e95c2f.js similarity index 92% rename from b479fc9a.9f8c87d7.js rename to b5eab6bb.93e95c2f.js index 449df5be02..e7c7103603 100644 --- a/b479fc9a.9f8c87d7.js +++ b/b5eab6bb.93e95c2f.js @@ -1,2 +1,2 @@ -/*! For license information please see b479fc9a.9f8c87d7.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 s})),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(449)),i=n(456),c=(n(448),n(453)),l=(n(457),{last_modified_on:"2024-04-10",$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/acarranoqovery",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:"Installation",id:"installation",children:[]},{value:"Conclusion",id:"conclusion",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)("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 a dedicated Qovery project and environment to deploy Datadog (example: Project=Tooling, Environment=Production)"),Object(o.b)("li",{parentName:"ul"},"You have a Datadog account"),Object(o.b)("li",{parentName:"ul"},"You have already created a ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://docs.datadoghq.com/account_management/api-app-keys/#api-keys"}),"Datadog API Key")))),Object(o.b)("h2",{id:"installation"},"Installation"),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:"add-the-datadog-helm-repository"},"Add the Datadog helm repository"),Object(o.b)("p",null,"Add the Datadog helm repository in your Qovery settings by following ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/helm-repository/"}),"this documentation")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Repository name: ",Object(o.b)("inlineCode",{parentName:"li"},"Datadog")),Object(o.b)("li",{parentName:"ul"},"Kind: ",Object(o.b)("inlineCode",{parentName:"li"},"HTTPS")),Object(o.b)("li",{parentName:"ul"},"Repository URL: ",Object(o.b)("inlineCode",{parentName:"li"},"https://helm.datadoghq.com")))),Object(o.b)("li",null,Object(o.b)("h4",{id:"create-the-datadog-service-within-qovery"},"Create the datadog service within Qovery"),Object(o.b)("p",null,"Create the Datadog helm service in the Qovery environment of your choice (preferrably within a dedicated Tooling project) by following ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/"}),"this documentation")," and these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"General:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Application name: ",Object(o.b)("inlineCode",{parentName:"li"},"Datadog")),Object(o.b)("li",{parentName:"ul"},"Source:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Helm source: ",Object(o.b)("inlineCode",{parentName:"li"},"Helm repository")),Object(o.b)("li",{parentName:"ul"},"Repository: ",Object(o.b)("inlineCode",{parentName:"li"},"Datadog")," (the name given during the datadog helm repository added in the previous step)"),Object(o.b)("li",{parentName:"ul"},"Chart name: ",Object(o.b)("inlineCode",{parentName:"li"},"datadog")),Object(o.b)("li",{parentName:"ul"},"Version: ",Object(o.b)("inlineCode",{parentName:"li"},"3.49.5")," (this is the version we used for this setup, update it based on the chosen version)"),Object(o.b)("li",{parentName:"ul"},"Allow cluster-wide resources \u2714\ufe0f"))))),Object(o.b)("li",{parentName:"ul"},"Values",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Values override as file:"),Object(o.b)("li",{parentName:"ul"},"File source: ",Object(o.b)("inlineCode",{parentName:"li"},"Raw YAML")),Object(o.b)("li",{parentName:"ul"},"Raw YAML:")))),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),"# The following YAML contains the minimum configuration required to deploy the Datadog Agent\n# on your cluster. Update it accordingly to your needs\ndatadog:\n # here we use a Qovery secret to retrieve the Datadog API Key (See next step)\n apiKey: qovery.env.DD_API_KEY\n # Update the site depending on where you want to store your data in Datadog\n site: datadoghq.eu\n # Update the cluster name with the name of your choice\n clusterName: qoverycluster\n")),Object(o.b)("p",null,"There are many other values you can set and modify the Datadog agent behaviour. 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)("p",null,"Now get to the last step and just ",Object(o.b)("inlineCode",{parentName:"p"},"Create")," the service on Qovery.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"store-the-datadog-api-key-as-secret"},"Store the Datadog API Key as secret"),Object(o.b)("p",null,"In the previous step we have assigned the macro ",Object(o.b)("inlineCode",{parentName:"p"},"qovery.env.DD_API_KEY")," to the API Key value. In this step we will create this secret within the Qovery console."),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Open the service overview of the created Datadog service"),Object(o.b)("li",{parentName:"ul"},"Enter the ",Object(o.b)("inlineCode",{parentName:"li"},"Variables")," section"),Object(o.b)("li",{parentName:"ul"},"Add a new Variable with:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Variable = DD_API_KEY"),Object(o.b)("li",{parentName:"ul"},"Value = "),Object(o.b)("li",{parentName:"ul"},"Scope = Service (so that it is accessible only to this service)"),Object(o.b)("li",{parentName:"ul"},"Secret variable \u2714\ufe0f")))),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/datadog-secret.png",alt:"Datadog - API Key"})),Object(o.b)("p",null,"If you need more information on how to manage your environment variables, have a look at ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"this documentation"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"deploy-your-chart"},"Deploy your chart"),Object(o.b)("p",null,"Open the ",Object(o.b)("inlineCode",{parentName:"p"},"Play")," button and trigger the deployment of your chart (see point 1 in the picture below)."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/deploy.png",alt:"Datadog - Deploy"})),Object(o.b)("p",null,"You can follow the deployment and access the deployment logs by pressing the ",Object(o.b)("inlineCode",{parentName:"p"},"Log")," button (see point 2 in the picutre above)."),Object(o.b)("p",null,"Once the deployment is completed, you should see the Datadog agent pods and their status directly within the Qovery console."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/datadog-pods.png",alt:"Datadog - Pods"})),Object(o.b)("p",null,"You can also look at the Pod logs by pressing the ",Object(o.b)("inlineCode",{parentName:"p"},"Log")," button.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"verify-the-setup-on-datadog"},"Verify the setup on Datadog"),Object(o.b)("p",null,"Access again your Datadog interface and access the Infrastructure > Containers > Kubernetes sections. You should now see the data coming from your Qovery cluster"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/datadog-console.png",alt:"Datadog - Console"}))))),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"),"."))}d.isMDXComponent=!0},447: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)},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,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(n),p=a,m=b["".concat(i,".").concat(p)]||b[p]||d[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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),c=n(458),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),d=Object(r.useRef)(!1),p=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!p&&b&&window.docusaurus.prefetch(u),function(){p&&t&&t.disconnect()}}),[u,p,b]),u&&b?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;p&&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}))}},455:function(e,t,n){"use strict";var a=n(459),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("&"):""}},456:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(447),n(455)),i=n.n(o);n(133);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),b=u[0],d=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 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"),"."))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(454),i=n(447),c=n.n(i);n(134);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,b=e.to,d=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:b,target:u,className:d},p):r.a.createElement(o.a,{to:b,className:d},p)}},458:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},459: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.93e95c2f.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[205],{356: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 d}));var a=n(1),r=n(9),o=(n(0),n(451)),i=n(458),c=(n(450),n(455)),l=(n(459),{last_modified_on:"2024-04-10",$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/acarranoqovery",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:"Installation",id:"installation",children:[]},{value:"Conclusion",id:"conclusion",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)("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 a dedicated Qovery project and environment to deploy Datadog (example: Project=Tooling, Environment=Production)"),Object(o.b)("li",{parentName:"ul"},"You have a Datadog account"),Object(o.b)("li",{parentName:"ul"},"You have already created a ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://docs.datadoghq.com/account_management/api-app-keys/#api-keys"}),"Datadog API Key")))),Object(o.b)("h2",{id:"installation"},"Installation"),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:"add-the-datadog-helm-repository"},"Add the Datadog helm repository"),Object(o.b)("p",null,"Add the Datadog helm repository in your Qovery settings by following ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/helm-repository/"}),"this documentation")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Repository name: ",Object(o.b)("inlineCode",{parentName:"li"},"Datadog")),Object(o.b)("li",{parentName:"ul"},"Kind: ",Object(o.b)("inlineCode",{parentName:"li"},"HTTPS")),Object(o.b)("li",{parentName:"ul"},"Repository URL: ",Object(o.b)("inlineCode",{parentName:"li"},"https://helm.datadoghq.com")))),Object(o.b)("li",null,Object(o.b)("h4",{id:"create-the-datadog-service-within-qovery"},"Create the datadog service within Qovery"),Object(o.b)("p",null,"Create the Datadog helm service in the Qovery environment of your choice (preferrably within a dedicated Tooling project) by following ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/"}),"this documentation")," and these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"General:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Application name: ",Object(o.b)("inlineCode",{parentName:"li"},"Datadog")),Object(o.b)("li",{parentName:"ul"},"Source:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Helm source: ",Object(o.b)("inlineCode",{parentName:"li"},"Helm repository")),Object(o.b)("li",{parentName:"ul"},"Repository: ",Object(o.b)("inlineCode",{parentName:"li"},"Datadog")," (the name given during the datadog helm repository added in the previous step)"),Object(o.b)("li",{parentName:"ul"},"Chart name: ",Object(o.b)("inlineCode",{parentName:"li"},"datadog")),Object(o.b)("li",{parentName:"ul"},"Version: ",Object(o.b)("inlineCode",{parentName:"li"},"3.49.5")," (this is the version we used for this setup, update it based on the chosen version)"),Object(o.b)("li",{parentName:"ul"},"Allow cluster-wide resources \u2714\ufe0f"))))),Object(o.b)("li",{parentName:"ul"},"Values",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Values override as file:"),Object(o.b)("li",{parentName:"ul"},"File source: ",Object(o.b)("inlineCode",{parentName:"li"},"Raw YAML")),Object(o.b)("li",{parentName:"ul"},"Raw YAML:")))),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),"# The following YAML contains the minimum configuration required to deploy the Datadog Agent\n# on your cluster. Update it accordingly to your needs\ndatadog:\n # here we use a Qovery secret to retrieve the Datadog API Key (See next step)\n apiKey: qovery.env.DD_API_KEY\n # Update the site depending on where you want to store your data in Datadog\n site: datadoghq.eu\n # Update the cluster name with the name of your choice\n clusterName: qoverycluster\n")),Object(o.b)("p",null,"There are many other values you can set and modify the Datadog agent behaviour. 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)("p",null,"Now get to the last step and just ",Object(o.b)("inlineCode",{parentName:"p"},"Create")," the service on Qovery.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"store-the-datadog-api-key-as-secret"},"Store the Datadog API Key as secret"),Object(o.b)("p",null,"In the previous step we have assigned the macro ",Object(o.b)("inlineCode",{parentName:"p"},"qovery.env.DD_API_KEY")," to the API Key value. In this step we will create this secret within the Qovery console."),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Open the service overview of the created Datadog service"),Object(o.b)("li",{parentName:"ul"},"Enter the ",Object(o.b)("inlineCode",{parentName:"li"},"Variables")," section"),Object(o.b)("li",{parentName:"ul"},"Add a new Variable with:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Variable = DD_API_KEY"),Object(o.b)("li",{parentName:"ul"},"Value = "),Object(o.b)("li",{parentName:"ul"},"Scope = Service (so that it is accessible only to this service)"),Object(o.b)("li",{parentName:"ul"},"Secret variable \u2714\ufe0f")))),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/datadog-secret.png",alt:"Datadog - API Key"})),Object(o.b)("p",null,"If you need more information on how to manage your environment variables, have a look at ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"this documentation"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"deploy-your-chart"},"Deploy your chart"),Object(o.b)("p",null,"Open the ",Object(o.b)("inlineCode",{parentName:"p"},"Play")," button and trigger the deployment of your chart (see point 1 in the picture below)."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/deploy.png",alt:"Datadog - Deploy"})),Object(o.b)("p",null,"You can follow the deployment and access the deployment logs by pressing the ",Object(o.b)("inlineCode",{parentName:"p"},"Log")," button (see point 2 in the picutre above)."),Object(o.b)("p",null,"Once the deployment is completed, you should see the Datadog agent pods and their status directly within the Qovery console."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/datadog-pods.png",alt:"Datadog - Pods"})),Object(o.b)("p",null,"You can also look at the Pod logs by pressing the ",Object(o.b)("inlineCode",{parentName:"p"},"Log")," button.")),Object(o.b)("li",null,Object(o.b)("h4",{id:"verify-the-setup-on-datadog"},"Verify the setup on Datadog"),Object(o.b)("p",null,"Access again your Datadog interface and access the Infrastructure > Containers > Kubernetes sections. You should now see the data coming from your Qovery cluster"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/kubernetes-observability-and-monitoring-with-datadog/datadog-console.png",alt:"Datadog - Console"}))))),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"),"."))}d.isMDXComponent=!0},449: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)},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,o=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=u(n),p=a,m=b["".concat(i,".").concat(p)]||b[p]||d[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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),c=n(460),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),d=Object(r.useRef)(!1),p=s.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!p&&b&&window.docusaurus.prefetch(u),function(){p&&t&&t.disconnect()}}),[u,p,b]),u&&b?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;p&&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}))}},457:function(e,t,n){"use strict";var a=n(461),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("&"):""}},458:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(449),n(457)),i=n.n(o);n(133);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),b=u[0],d=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 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"),"."))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(456),i=n(449),c=n.n(i);n(134);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,b=e.to,d=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:b,target:u,className:d},p):r.a.createElement(o.a,{to:b,className:d},p)}},460:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},461: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.cb777a83.js.LICENSE.txt b/b5eab6bb.93e95c2f.js.LICENSE.txt similarity index 100% rename from b74d0aaa.cb777a83.js.LICENSE.txt rename to b5eab6bb.93e95c2f.js.LICENSE.txt diff --git a/b7280cb5.7c939296.js b/b7280cb5.8d594c09.js similarity index 93% rename from b7280cb5.7c939296.js rename to b7280cb5.8d594c09.js index 02f89a36b7..a180e34e74 100644 --- a/b7280cb5.7c939296.js +++ b/b7280cb5.8d594c09.js @@ -1,2 +1,2 @@ -/*! For license information please see b7280cb5.7c939296.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[204],{355: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(449)),i=n(448),c=n(456),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},447: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}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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.8d594c09.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[206],{357: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(451)),i=n(450),c=n(458),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},449: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}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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.2326bb0a.js.LICENSE.txt b/b7280cb5.8d594c09.js.LICENSE.txt similarity index 100% rename from b76eb9a9.2326bb0a.js.LICENSE.txt rename to b7280cb5.8d594c09.js.LICENSE.txt diff --git a/b74d0aaa.cb777a83.js b/b74d0aaa.b6908391.js similarity index 96% rename from b74d0aaa.cb777a83.js rename to b74d0aaa.b6908391.js index f6693b6c70..4bd609165b 100644 --- a/b74d0aaa.cb777a83.js +++ b/b74d0aaa.b6908391.js @@ -1,2 +1,2 @@ -/*! For license information please see b74d0aaa.cb777a83.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[205],{356: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(449)),i=t(448),s=(t(453),t(457),{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},447: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}},452: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""}}})},453:function(e,n,t){"use strict";t(452);var a=t(0),r=t.n(a),o=t(448);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)}},454:function(e,n,t){"use strict";var a=t(1),r=t(0),o=t.n(r),i=t(39),s=t(458),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}))}},457:function(e,n,t){"use strict";var a=t(0),r=t.n(a),o=t(454),i=t(447),s=t.n(i);t(134);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)}},458: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.b6908391.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[207],{358: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(451)),i=t(450),s=(t(455),t(459),{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},449: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}},454: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""}}})},455:function(e,n,t){"use strict";t(454);var a=t(0),r=t.n(a),o=t(450);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)}},456:function(e,n,t){"use strict";var a=t(1),r=t(0),o=t.n(r),i=t(39),s=t(460),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}))}},459:function(e,n,t){"use strict";var a=t(0),r=t.n(a),o=t(456),i=t(449),s=t.n(i);t(134);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)}},460: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.e8a90674.js.LICENSE.txt b/b74d0aaa.b6908391.js.LICENSE.txt similarity index 100% rename from b79e7411.e8a90674.js.LICENSE.txt rename to b74d0aaa.b6908391.js.LICENSE.txt diff --git a/b76eb9a9.2326bb0a.js b/b76eb9a9.2326bb0a.js deleted file mode 100644 index 057b7fa7e1..0000000000 --- a/b76eb9a9.2326bb0a.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see b76eb9a9.2326bb0a.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[206],{357: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(449)),i=n(453),c=n(456),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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.e91d2930.js b/b76eb9a9.e91d2930.js new file mode 100644 index 0000000000..a71bf384af --- /dev/null +++ b/b76eb9a9.e91d2930.js @@ -0,0 +1,2 @@ +/*! For license information please see b76eb9a9.e91d2930.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[208],{359: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(451)),i=n(455),c=n(458),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 a DaemonSet in a Karpenter context",permalink:"/guides/advanced/deploy-daemonset-with-karpenter"}},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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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.486cf83f.js.LICENSE.txt b/b76eb9a9.e91d2930.js.LICENSE.txt similarity index 100% rename from b7d53051.486cf83f.js.LICENSE.txt rename to b76eb9a9.e91d2930.js.LICENSE.txt diff --git a/b79e7411.e8a90674.js b/b79e7411.dcc44465.js similarity index 85% rename from b79e7411.e8a90674.js rename to b79e7411.dcc44465.js index 6f8b4b17bc..3fda433739 100644 --- a/b79e7411.e8a90674.js +++ b/b79e7411.dcc44465.js @@ -1,2 +1,2 @@ -/*! For license information please see b79e7411.e8a90674.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[207],{358: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(449)),i=(n(457),n(448),n(453),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},454:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(458),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}))}},457:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(454),i=n(447),c=n.n(i);n(134);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)}},458: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.dcc44465.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[209],{360: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(451)),i=(n(459),n(450),n(455),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},456:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(460),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}))}},459:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(456),i=n(449),c=n.n(i);n(134);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)}},460: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.02a79b48.js.LICENSE.txt b/b79e7411.dcc44465.js.LICENSE.txt similarity index 100% rename from b8490823.02a79b48.js.LICENSE.txt rename to b79e7411.dcc44465.js.LICENSE.txt diff --git a/b7d53051.486cf83f.js b/b7d53051.486cf83f.js deleted file mode 100644 index e16b995dd6..0000000000 --- a/b7d53051.486cf83f.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see b7d53051.486cf83f.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[208],{359: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(449)),i=(n(456),n(453),n(448),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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.dd145f54.js b/b7d53051.dd145f54.js new file mode 100644 index 0000000000..67381e6173 --- /dev/null +++ b/b7d53051.dd145f54.js @@ -0,0 +1,2 @@ +/*! For license information please see b7d53051.dd145f54.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[210],{361: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(451)),i=(n(458),n(455),n(450),{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:"Deploy a DaemonSet in a Karpenter context",permalink:"/guides/advanced/deploy-daemonset-with-karpenter"},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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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/b91b4421.2eb7323c.js.LICENSE.txt b/b7d53051.dd145f54.js.LICENSE.txt similarity index 100% rename from b91b4421.2eb7323c.js.LICENSE.txt rename to b7d53051.dd145f54.js.LICENSE.txt diff --git a/b8490823.02a79b48.js b/b8490823.3f179731.js similarity index 91% rename from b8490823.02a79b48.js rename to b8490823.3f179731.js index da8c2a4170..c6c0063847 100644 --- a/b8490823.02a79b48.js +++ b/b8490823.3f179731.js @@ -1,2 +1,2 @@ -/*! For license information please see b8490823.02a79b48.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[209],{360: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(449)),o=(n(457),n(448)),c=(n(453),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var i=n(0),a=n.n(i),r=n(448);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)}},454:function(e,t,n){"use strict";var i=n(1),a=n(0),r=n.n(a),o=n(39),c=n(458),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}))}},457:function(e,t,n){"use strict";var i=n(0),a=n.n(i),r=n(454),o=n(447),c=n.n(o);n(134);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)}},458: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.3f179731.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[211],{362: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(451)),o=(n(459),n(450)),c=(n(455),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var i=n(0),a=n.n(i),r=n(450);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)}},456:function(e,t,n){"use strict";var i=n(1),a=n(0),r=n.n(a),o=n(39),c=n(460),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}))}},459:function(e,t,n){"use strict";var i=n(0),a=n.n(i),r=n(456),o=n(449),c=n.n(o);n(134);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)}},460: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.7b938794.js.LICENSE.txt b/b8490823.3f179731.js.LICENSE.txt similarity index 100% rename from b98931a2.7b938794.js.LICENSE.txt rename to b8490823.3f179731.js.LICENSE.txt diff --git a/b91b4421.2eb7323c.js b/b91b4421.6fd86cfc.js similarity index 94% rename from b91b4421.2eb7323c.js rename to b91b4421.6fd86cfc.js index 5992553685..f54c0b8dc3 100644 --- a/b91b4421.2eb7323c.js +++ b/b91b4421.6fd86cfc.js @@ -1,2 +1,2 @@ -/*! For license information please see b91b4421.2eb7323c.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[210],{361: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 b}));var a=n(1),i=n(9),r=(n(0),n(449)),o=n(456),l=n(448),c={last_modified_on:"2024-02-26",title:"Validate the installation",description:"Learn how to validate that everything works as expected on your Qovery installation"},s={id:"getting-started/install-qovery/kubernetes/validate-installation",title:"Validate the installation",description:"Learn how to validate that everything works as expected on your Qovery installation",source:"@site/docs/getting-started/install-qovery/kubernetes/validate-installation.md",permalink:"/docs/getting-started/install-qovery/kubernetes/validate-installation",sidebar:"docs",previous:{title:"Configuration",permalink:"/docs/getting-started/install-qovery/kubernetes/byok-config"},next:{title:"FAQ",permalink:"/docs/getting-started/install-qovery/kubernetes/faq"}},p=[{value:"Step 1: verify container deployment",id:"step-1-verify-container-deployment",children:[]},{value:"Step 2: verify application public exposure and TLS",id:"step-2-verify-application-public-exposure-and-tls",children:[]},{value:"Step 3: verify storage availability",id:"step-3-verify-storage-availability",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)("p",null,"To verify that everything works fine on brand new installation, we will deploy a few simple applications."),Object(r.b)("h2",{id:"step-1-verify-container-deployment"},"Step 1: verify container deployment"),Object(r.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,"Create an environment",Object(r.b)("p",null,"Open the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console"),' and access the "Environment" section. '),Object(r.b)("p",null,"Add a ",Object(r.b)("inlineCode",{parentName:"p"},"new environment")," and select as target the cluster that was created in the previous step.")),Object(r.b)("li",null,"Create an application",Object(r.b)("p",null,"Within this environment, create a new service of type ",Object(r.b)("inlineCode",{parentName:"p"},"Application"),"."),Object(r.b)("p",null,"Fill the fields this way:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Name: test"),Object(r.b)("li",{parentName:"ul"},"Application source: Container Registry"),Object(r.b)("li",{parentName:"ul"},"Registry: Dockerhub public"),Object(r.b)("li",{parentName:"ul"},"image name: ",Object(r.b)("inlineCode",{parentName:"li"},"stefanprodan/podinfo")),Object(r.b)("li",{parentName:"ul"},"image tag: ",Object(r.b)("inlineCode",{parentName:"li"},"6.5.2"))),Object(r.b)("p",null,"Click on ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," until the installation recap is displayed. Now click on ",Object(r.b)("inlineCode",{parentName:"p"},"Create and deploy"),".")),Object(r.b)("li",null,"Follow the deployment",Object(r.b)("p",null,"The application will start the deployment and you can follow it opening the ",Object(r.b)("inlineCode",{parentName:"p"},"Log")," button or by pressing on the ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment status")),Object(r.b)("p",{align:"left"},Object(r.b)("img",{src:"/img/install-qovery/aws/test-service.png",alt:"Test container"})),Object(r.b)("p",null,"After a few seconds, the deployment should end and the message ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment of Container succeeded")," should be displayed in the deployment logs."),Object(r.b)("p",null,"You should now see at least one pod running on your cluster with the specified container.")),Object(r.b)("li",null,"Verify Qovery functionalities",Object(r.b)("p",null,"Click on the log button to access the ",Object(r.b)("inlineCode",{parentName:"p"},"Live logs")," section."),Object(r.b)("p",null,"You should be able to:\n1) access the log of the deployed application\n2) retrieve the running status of the application from the element next to the ",Object(r.b)("inlineCode",{parentName:"p"},"Live logs")," tab"),Object(r.b)("p",{align:"left"},Object(r.b)("img",{src:"/img/install-qovery/aws/check-logs.png",alt:"Test container"}))))),Object(r.b)("h2",{id:"step-2-verify-application-public-exposure-and-tls"},"Step 2: verify application public exposure and TLS"),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"This step should be run only if you have enabled the services ",Object(r.b)("inlineCode",{parentName:"p"},"external-dns"),", ",Object(r.b)("inlineCode",{parentName:"p"},"cert-manager"),", ",Object(r.b)("inlineCode",{parentName:"p"},"cert-manager-config")," and ",Object(r.b)("inlineCode",{parentName:"p"},"qovery-cert-manager-webhook")," in your values.yaml file during the installation.")),Object(r.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,"Expose container publicly",Object(r.b)("p",null,"Open the settings of the container created in the step 1. Open the section ",Object(r.b)("inlineCode",{parentName:"p"},"Port")),Object(r.b)("p",null,"Add one port with:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Application port: 9898"),Object(r.b)("li",{parentName:"ul"},"Protocol: HTTP"),Object(r.b)("li",{parentName:"ul"},"Publicly exposed: true")),Object(r.b)("p",null,"Add the port and then click on ",Object(r.b)("inlineCode",{parentName:"p"},"Re-deploy now")," banner. ")),Object(r.b)("li",null,"Follow the deployment",Object(r.b)("p",null,"The application will start the deployment and you can follow it opening the ",Object(r.b)("inlineCode",{parentName:"p"},"Log")," button or by pressing on the ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment status")),Object(r.b)("p",{align:"left"},Object(r.b)("img",{src:"/img/install-qovery/aws/test-service.png",alt:"Test container"})),Object(r.b)("p",null,"After a few seconds, the deployment should end and the message ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment of Container succeeded")," should be displayed in the deployment logs.")),Object(r.b)("li",null,"Check the accessibility",Object(r.b)("p",null,'Click on the "Link" button and select one of the URLs of the list.'),Object(r.b)("p",{align:"left"},Object(r.b)("img",{src:"/img/install-qovery/aws/link.png",alt:"Application Link"})),Object(r.b)("p",null,"You should be able to access the podinfo homepage with a valid certificate.")))),Object(r.b)("h2",{id:"step-3-verify-storage-availability"},"Step 3: verify storage availability"),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"This step should be run only if you have enabled the services ",Object(r.b)("inlineCode",{parentName:"p"},"q-storageclass-aws")," and ",Object(r.b)("inlineCode",{parentName:"p"},"aws-ebs-csi-driver")," in your values.yaml file during the installation (or you already have the CSI plugin activated on your AWS cluster).")),Object(r.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,"Create a database",Object(r.b)("p",null,"Go back to the environment page and create a new service of type ",Object(r.b)("inlineCode",{parentName:"p"},"Database"),"."),Object(r.b)("p",null,"Fill the fields this way:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Name: test-db"),Object(r.b)("li",{parentName:"ul"},"Database Mode: Container"),Object(r.b)("li",{parentName:"ul"},"Database type: Mysql"),Object(r.b)("li",{parentName:"ul"},"version: select one from the list"),Object(r.b)("li",{parentName:"ul"},"accessibility: private")),Object(r.b)("p",null,"Click on ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," until the installation recap is displayed. Now click on ",Object(r.b)("inlineCode",{parentName:"p"},"Create and deploy"),".")),Object(r.b)("li",null,"Follow the deployment",Object(r.b)("p",null,"The databse will start the deployment and you can follow it opening the ",Object(r.b)("inlineCode",{parentName:"p"},"Log")," button or by pressing on the ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment status")),Object(r.b)("p",null,"After a few seconds, the deployment should end and the message ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment of Database succeeded")," should be displayed in the deployment logs."),Object(r.b)("p",null,"You should now see at least one pod running on your cluster with the specified container and you should be able to access your database from within you cluster (you can retrieve the connection string via the button ",Object(r.b)("inlineCode",{parentName:"p"},"Connection URI")," available in the database overview targetCPUUtilizationPercentage)")))))}b.isMDXComponent=!0},447: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):l({},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)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,o=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),u=p(n),d=a,f=u["".concat(o,".").concat(d)]||u[d]||b[d]||r;return n?i.a.createElement(f,l({ref:t},s,{components:n})):i.a.createElement(f,l({ref:t},s))}));function f(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 l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,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:i(c,n);s>l;)t[l++]=e;return t}},455:function(e,t,n){"use strict";var a=n(459),i=n(51);function r(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=i({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("="),i=t.shift(),r=t.length>0?t.join("="):void 0;r=void 0===r?null:decodeURIComponent(r),n(decodeURIComponent(i),r,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?[r(t,e),"[",a,"]"].join(""):[r(t,e),"[",r(a,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=i({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var i=e[a];if(void 0===i)return"";if(null===i)return r(a,t);if(Array.isArray(i)){var o=[];return i.slice().forEach((function(e){void 0!==e&&o.push(n(a,e,o.length))})),o.join("&")}return r(a,t)+"="+r(i,t)})).filter((function(e){return e.length>0})).join("&"):""}},456:function(e,t,n){"use strict";var a=n(0),i=n.n(a),r=(n(447),n(455)),o=n.n(r);n(133);t.a=function(e){var t=e.children,n=e.headingDepth,r=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(a.useState)(null),u=p[0],b=p[1];return i.a.createElement("div",{className:"steps steps--h"+n},t,!r&&!u&&i.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",i.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",i.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&i.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",i.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},459: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 b91b4421.6fd86cfc.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[212],{363: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 b}));var a=n(1),i=n(9),r=(n(0),n(451)),o=n(458),l=n(450),c={last_modified_on:"2024-02-26",title:"Validate the installation",description:"Learn how to validate that everything works as expected on your Qovery installation"},s={id:"getting-started/install-qovery/kubernetes/validate-installation",title:"Validate the installation",description:"Learn how to validate that everything works as expected on your Qovery installation",source:"@site/docs/getting-started/install-qovery/kubernetes/validate-installation.md",permalink:"/docs/getting-started/install-qovery/kubernetes/validate-installation",sidebar:"docs",previous:{title:"Configuration",permalink:"/docs/getting-started/install-qovery/kubernetes/byok-config"},next:{title:"FAQ",permalink:"/docs/getting-started/install-qovery/kubernetes/faq"}},p=[{value:"Step 1: verify container deployment",id:"step-1-verify-container-deployment",children:[]},{value:"Step 2: verify application public exposure and TLS",id:"step-2-verify-application-public-exposure-and-tls",children:[]},{value:"Step 3: verify storage availability",id:"step-3-verify-storage-availability",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)("p",null,"To verify that everything works fine on brand new installation, we will deploy a few simple applications."),Object(r.b)("h2",{id:"step-1-verify-container-deployment"},"Step 1: verify container deployment"),Object(r.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,"Create an environment",Object(r.b)("p",null,"Open the ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery console"),' and access the "Environment" section. '),Object(r.b)("p",null,"Add a ",Object(r.b)("inlineCode",{parentName:"p"},"new environment")," and select as target the cluster that was created in the previous step.")),Object(r.b)("li",null,"Create an application",Object(r.b)("p",null,"Within this environment, create a new service of type ",Object(r.b)("inlineCode",{parentName:"p"},"Application"),"."),Object(r.b)("p",null,"Fill the fields this way:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Name: test"),Object(r.b)("li",{parentName:"ul"},"Application source: Container Registry"),Object(r.b)("li",{parentName:"ul"},"Registry: Dockerhub public"),Object(r.b)("li",{parentName:"ul"},"image name: ",Object(r.b)("inlineCode",{parentName:"li"},"stefanprodan/podinfo")),Object(r.b)("li",{parentName:"ul"},"image tag: ",Object(r.b)("inlineCode",{parentName:"li"},"6.5.2"))),Object(r.b)("p",null,"Click on ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," until the installation recap is displayed. Now click on ",Object(r.b)("inlineCode",{parentName:"p"},"Create and deploy"),".")),Object(r.b)("li",null,"Follow the deployment",Object(r.b)("p",null,"The application will start the deployment and you can follow it opening the ",Object(r.b)("inlineCode",{parentName:"p"},"Log")," button or by pressing on the ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment status")),Object(r.b)("p",{align:"left"},Object(r.b)("img",{src:"/img/install-qovery/aws/test-service.png",alt:"Test container"})),Object(r.b)("p",null,"After a few seconds, the deployment should end and the message ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment of Container succeeded")," should be displayed in the deployment logs."),Object(r.b)("p",null,"You should now see at least one pod running on your cluster with the specified container.")),Object(r.b)("li",null,"Verify Qovery functionalities",Object(r.b)("p",null,"Click on the log button to access the ",Object(r.b)("inlineCode",{parentName:"p"},"Live logs")," section."),Object(r.b)("p",null,"You should be able to:\n1) access the log of the deployed application\n2) retrieve the running status of the application from the element next to the ",Object(r.b)("inlineCode",{parentName:"p"},"Live logs")," tab"),Object(r.b)("p",{align:"left"},Object(r.b)("img",{src:"/img/install-qovery/aws/check-logs.png",alt:"Test container"}))))),Object(r.b)("h2",{id:"step-2-verify-application-public-exposure-and-tls"},"Step 2: verify application public exposure and TLS"),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"This step should be run only if you have enabled the services ",Object(r.b)("inlineCode",{parentName:"p"},"external-dns"),", ",Object(r.b)("inlineCode",{parentName:"p"},"cert-manager"),", ",Object(r.b)("inlineCode",{parentName:"p"},"cert-manager-config")," and ",Object(r.b)("inlineCode",{parentName:"p"},"qovery-cert-manager-webhook")," in your values.yaml file during the installation.")),Object(r.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,"Expose container publicly",Object(r.b)("p",null,"Open the settings of the container created in the step 1. Open the section ",Object(r.b)("inlineCode",{parentName:"p"},"Port")),Object(r.b)("p",null,"Add one port with:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Application port: 9898"),Object(r.b)("li",{parentName:"ul"},"Protocol: HTTP"),Object(r.b)("li",{parentName:"ul"},"Publicly exposed: true")),Object(r.b)("p",null,"Add the port and then click on ",Object(r.b)("inlineCode",{parentName:"p"},"Re-deploy now")," banner. ")),Object(r.b)("li",null,"Follow the deployment",Object(r.b)("p",null,"The application will start the deployment and you can follow it opening the ",Object(r.b)("inlineCode",{parentName:"p"},"Log")," button or by pressing on the ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment status")),Object(r.b)("p",{align:"left"},Object(r.b)("img",{src:"/img/install-qovery/aws/test-service.png",alt:"Test container"})),Object(r.b)("p",null,"After a few seconds, the deployment should end and the message ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment of Container succeeded")," should be displayed in the deployment logs.")),Object(r.b)("li",null,"Check the accessibility",Object(r.b)("p",null,'Click on the "Link" button and select one of the URLs of the list.'),Object(r.b)("p",{align:"left"},Object(r.b)("img",{src:"/img/install-qovery/aws/link.png",alt:"Application Link"})),Object(r.b)("p",null,"You should be able to access the podinfo homepage with a valid certificate.")))),Object(r.b)("h2",{id:"step-3-verify-storage-availability"},"Step 3: verify storage availability"),Object(r.b)(l.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"This step should be run only if you have enabled the services ",Object(r.b)("inlineCode",{parentName:"p"},"q-storageclass-aws")," and ",Object(r.b)("inlineCode",{parentName:"p"},"aws-ebs-csi-driver")," in your values.yaml file during the installation (or you already have the CSI plugin activated on your AWS cluster).")),Object(r.b)(o.a,{headingDepth:3,mdxType:"Steps"},Object(r.b)("ol",null,Object(r.b)("li",null,"Create a database",Object(r.b)("p",null,"Go back to the environment page and create a new service of type ",Object(r.b)("inlineCode",{parentName:"p"},"Database"),"."),Object(r.b)("p",null,"Fill the fields this way:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Name: test-db"),Object(r.b)("li",{parentName:"ul"},"Database Mode: Container"),Object(r.b)("li",{parentName:"ul"},"Database type: Mysql"),Object(r.b)("li",{parentName:"ul"},"version: select one from the list"),Object(r.b)("li",{parentName:"ul"},"accessibility: private")),Object(r.b)("p",null,"Click on ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," until the installation recap is displayed. Now click on ",Object(r.b)("inlineCode",{parentName:"p"},"Create and deploy"),".")),Object(r.b)("li",null,"Follow the deployment",Object(r.b)("p",null,"The databse will start the deployment and you can follow it opening the ",Object(r.b)("inlineCode",{parentName:"p"},"Log")," button or by pressing on the ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment status")),Object(r.b)("p",null,"After a few seconds, the deployment should end and the message ",Object(r.b)("inlineCode",{parentName:"p"},"Deployment of Database succeeded")," should be displayed in the deployment logs."),Object(r.b)("p",null,"You should now see at least one pod running on your cluster with the specified container and you should be able to access your database from within you cluster (you can retrieve the connection string via the button ",Object(r.b)("inlineCode",{parentName:"p"},"Connection URI")," available in the database overview targetCPUUtilizationPercentage)")))))}b.isMDXComponent=!0},449: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):l({},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)}},d=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,o=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),u=p(n),d=a,f=u["".concat(o,".").concat(d)]||u[d]||b[d]||r;return n?i.a.createElement(f,l({ref:t},s,{components:n})):i.a.createElement(f,l({ref:t},s))}));function f(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 l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,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:i(c,n);s>l;)t[l++]=e;return t}},457:function(e,t,n){"use strict";var a=n(461),i=n(51);function r(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=i({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("="),i=t.shift(),r=t.length>0?t.join("="):void 0;r=void 0===r?null:decodeURIComponent(r),n(decodeURIComponent(i),r,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?[r(t,e),"[",a,"]"].join(""):[r(t,e),"[",r(a,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=i({encode:!0,strict:!0,arrayFormat:"none"},t));return e?Object.keys(e).sort().map((function(a){var i=e[a];if(void 0===i)return"";if(null===i)return r(a,t);if(Array.isArray(i)){var o=[];return i.slice().forEach((function(e){void 0!==e&&o.push(n(a,e,o.length))})),o.join("&")}return r(a,t)+"="+r(i,t)})).filter((function(e){return e.length>0})).join("&"):""}},458:function(e,t,n){"use strict";var a=n(0),i=n.n(a),r=(n(449),n(457)),o=n.n(r);n(133);t.a=function(e){var t=e.children,n=e.headingDepth,r=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(a.useState)(null),u=p[0],b=p[1];return i.a.createElement("div",{className:"steps steps--h"+n},t,!r&&!u&&i.a.createElement("div",{className:"steps--feedback"},"How was it? Did this tutorial work?\xa0\xa0",i.a.createElement("span",{className:"button button--sm button--primary",onClick:function(){return b("yes")}},"Yes"),"\xa0\xa0",i.a.createElement("a",{href:s,target:"_blank",className:"button button--sm button--primary"},"No")),"yes"==u&&i.a.createElement("div",{className:"steps--feedback steps--feedback--success"},"Thanks! If you're enjoying Qovery please consider ",i.a.createElement("a",{href:"https://github.com/qovery/documentation/",target:"_blank"},"starring our Github repo"),"."))}},461: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/ba43933d.134f4e52.js.LICENSE.txt b/b91b4421.6fd86cfc.js.LICENSE.txt similarity index 100% rename from ba43933d.134f4e52.js.LICENSE.txt rename to b91b4421.6fd86cfc.js.LICENSE.txt diff --git a/b98931a2.7b938794.js b/b98931a2.856d2539.js similarity index 89% rename from b98931a2.7b938794.js rename to b98931a2.856d2539.js index e89cd4abd2..d33c106d37 100644 --- a/b98931a2.7b938794.js +++ b/b98931a2.856d2539.js @@ -1,2 +1,2 @@ -/*! For license information please see b98931a2.7b938794.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[211],{362: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(449)),o=t(448),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},447: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.856d2539.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[213],{364: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(451)),o=t(450),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},449: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.78abdbb4.js.LICENSE.txt b/b98931a2.856d2539.js.LICENSE.txt similarity index 100% rename from bbedfc29.78abdbb4.js.LICENSE.txt rename to b98931a2.856d2539.js.LICENSE.txt diff --git a/e5653b8d.3e305717.js b/ba43933d.b7f3b508.js similarity index 91% rename from e5653b8d.3e305717.js rename to ba43933d.b7f3b508.js index 491dfc235f..dc6d5732e8 100644 --- a/e5653b8d.3e305717.js +++ b/ba43933d.b7f3b508.js @@ -1,2 +1,2 @@ -/*! For license information please see e5653b8d.3e305717.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[270],{422: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(449)),i=n(448),l=(n(453),n(457),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(458),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}))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(454),i=n(447),l=n.n(i);n(134);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)}},458: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.b7f3b508.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[214],{365: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(451)),i=n(450),l=(n(455),n(459),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(460),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}))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(456),i=n(449),l=n.n(i);n(134);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)}},460: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.83a36949.js.LICENSE.txt b/ba43933d.b7f3b508.js.LICENSE.txt similarity index 100% rename from bbfbe73c.83a36949.js.LICENSE.txt rename to ba43933d.b7f3b508.js.LICENSE.txt diff --git a/baf9cc25.92cdd67f.js b/baf9cc25.6faca4f1.js similarity index 96% rename from baf9cc25.92cdd67f.js rename to baf9cc25.6faca4f1.js index f972daae28..3876f89ab0 100644 --- a/baf9cc25.92cdd67f.js +++ b/baf9cc25.6faca4f1.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[213],{364: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(449)),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},449: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},448:function(e,t,a){"use strict";a(450);var n=a(0),o=a.n(n),r=a(447),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)}},452: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""}}})},453:function(e,t,a){"use strict";a(452);var n=a(0),o=a.n(n),r=a(448);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)}},454:function(e,t,a){"use strict";var n=a(1),o=a(0),r=a.n(o),l=a(39),c=a(458),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}))}},457:function(e,t,a){"use strict";var n=a(0),o=a.n(n),r=a(454),l=a(447),c=a.n(l);a(134);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)}},458:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},461:function(e,t,a){"use strict";var n=a(1),o=(a(465),a(462),a(52),a(29),a(22),a(21),a(0)),r=a.n(o),l=a(469),c=a(447),i=a.n(c),s=a(455),b=a.n(s),u=a(468),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])}},464: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([[216],{367: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(451)),l=a(463),c=a(466),i=a(450),s=a(455),b=(a(459),{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:"Integrate your application logs to Cloudwatch",permalink:"/guides/tutorial/cloudwatch-integration"}},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},450:function(e,t,a){"use strict";a(452);var n=a(0),o=a.n(n),r=a(449),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)}},454: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""}}})},455:function(e,t,a){"use strict";a(454);var n=a(0),o=a.n(n),r=a(450);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)}},456:function(e,t,a){"use strict";var n=a(1),o=a(0),r=a.n(o),l=a(39),c=a(460),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}))}},459:function(e,t,a){"use strict";var n=a(0),o=a.n(n),r=a(456),l=a(449),c=a.n(l);a(134);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)}},460:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},463:function(e,t,a){"use strict";var n=a(1),o=(a(467),a(464),a(52),a(29),a(22),a(21),a(0)),r=a.n(o),l=a(471),c=a(449),i=a.n(c),s=a(457),b=a.n(s),u=a(470),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])}},466: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/cbb976f4.22e76592.js b/bbedfc29.63239f49.js similarity index 93% rename from cbb976f4.22e76592.js rename to bbedfc29.63239f49.js index 5e928c5154..7bb75f1c83 100644 --- a/cbb976f4.22e76592.js +++ b/bbedfc29.63239f49.js @@ -1,2 +1,2 @@ -/*! For license information please see cbb976f4.22e76592.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 o})),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),i=(n(0),n(449)),o=(n(448),n(453),n(457),{last_modified_on:"2023-12-30",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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(i.b)("wrapper",Object(a.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(i.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(i.b)("inlineCode",{parentName:"p"},"Amazon SQS"),") to build a highly scalable backend."),Object(i.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(i.b)("h2",{id:"goal"},"Goal"),Object(i.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(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"We will use ",Object(i.b)("inlineCode",{parentName:"li"},"AWS Lambda")," to process events from the queue in a serverless way"),Object(i.b)("li",{parentName:"ul"},"We will use Qovery-managed backend application workers to process events from the queue")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/1.png",alt:"AWS SQS Lambda"})),Object(i.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(i.b)("p",null,"The backend application and workers servers that consume messages from the queue will be fully managed and deployed by Qovery."),Object(i.b)("p",null,"Let's get started."),Object(i.b)("h2",{id:"configure-sqs"},"Configure SQS"),Object(i.b)("p",null,"Open ",Object(i.b)("inlineCode",{parentName:"p"},"Amazon SQS")," service in AWS Console and click on ",Object(i.b)("inlineCode",{parentName:"p"},"Create Queue")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/2.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"We will use the ",Object(i.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(i.b)("inlineCode",{parentName:"p"},"Create"),"."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/3.png",alt:"AWS SQS Lambda"})),Object(i.b)("h2",{id:"create-message-producer"},"Create Message Producer"),Object(i.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(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/aws-sqs-example/blob/main/index.js"}),"here"),"."),Object(i.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(i.b)("pre",null,Object(i.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(i.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(i.b)("inlineCode",{parentName:"p"},"3000"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/4.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"Afterwards, we need to add two environment variables:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"accessKeyId")," - your AWS access key ID"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"secretAccessKey")," - your AWS secret access key")),Object(i.b)("p",null,"You can add them in ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variebles")," ",Object(i.b)("inlineCode",{parentName:"p"},"Secret")," section in your application settings:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/5.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/6.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"After all the setup is all done, click the ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy")," button - the application will be shortly deployed."),Object(i.b)("h2",{id:"create-lambda-consumers"},"Create Lambda Consumers"),Object(i.b)("p",null,"In AWS Console, open ",Object(i.b)("inlineCode",{parentName:"p"},"AWS Lambda")," panel."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/7.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"For the sake of the guide, we will use a simple ",Object(i.b)("inlineCode",{parentName:"p"},"hello-world")," lambda from AWS serverless app repository."),Object(i.b)("p",null,"Browse the app repository and pick the ",Object(i.b)("inlineCode",{parentName:"p"},"hello-world")," function as shown in the screenshot above, and deploy the function"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/8.png",alt:"AWS SQS Lambda"})),Object(i.b)("h2",{id:"create-lambda-trigger"},"Create Lambda Trigger"),Object(i.b)("p",null,"To make our Lambdas consume messages from SQS, we will need to add a ",Object(i.b)("inlineCode",{parentName:"p"},"Lambda Trigger")," in the SQS configuration."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/9.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"Click on ",Object(i.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(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/10.png",alt:"AWS SQS Lambda"})),Object(i.b)("h2",{id:"configure-permissions"},"Configure Permissions"),Object(i.b)("p",null,"Let's now grant our Lambda functions access to the SQS queue we created before."),Object(i.b)("p",null,"In our lambda view, click on ",Object(i.b)("inlineCode",{parentName:"p"},"Configure"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/11.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"Then, click on a role in ",Object(i.b)("inlineCode",{parentName:"p"},"Execution role")," to get redirected to a view where we can alter our Lambda permissions."),Object(i.b)("p",null,"In the role summary screen, click on ",Object(i.b)("inlineCode",{parentName:"p"},"Edit policy")," next to ",Object(i.b)("inlineCode",{parentName:"p"},"helloWorldrolePolicy")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/12.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"In the ",Object(i.b)("inlineCode",{parentName:"p"},"SQS")," section, grant permissions to all Read/Write options in the ",Object(i.b)("inlineCode",{parentName:"p"},"Actions")," ",Object(i.b)("inlineCode",{parentName:"p"},"Access level")," and accept the changes:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/13.png",alt:"AWS SQS Lambda"})),Object(i.b)("h2",{id:"test-lambda-as-an-sqs-consumer-flow"},"Test Lambda as an SQS Consumer Flow"),Object(i.b)("p",null,"To push messages to our SQS queue from the backend app deployed on Qovery, click on the ",Object(i.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(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/14.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"Now, in the ",Object(i.b)("inlineCode",{parentName:"p"},"Monitoring")," section of SQS in AWS Console, we will see messages received on metrics charts:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/15.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"To validate that our consumer Lambdas processed the messages, navigate to your lambda ",Object(i.b)("inlineCode",{parentName:"p"},"Monitor")," panel:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/16.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"In the ",Object(i.b)("inlineCode",{parentName:"p"},"Invocations")," chart, you'll notice that our Lambda was triggered several times by the messages sent over the SQS."),Object(i.b)("h2",{id:"conclusions"},"Conclusions"),Object(i.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},447: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 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)},m={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,i=e.originalType,o=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=b(n),d=a,p=u["".concat(o,".").concat(d)]||u[d]||m[d]||i;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 i=n.length,o=new Array(i);o[0]=d;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,o[1]=s;for(var l=2;l1?arguments[1]:void 0,n),c=o>2?arguments[2]:void 0,l=void 0===c?n:r(c,n);l>s;)t[s++]=e;return t}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),i=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),i=n.n(r),o=n(39),s=n(458),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),m=Object(r.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,u]),b&&u?i.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(b),m.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})):i.a.createElement("a",Object(a.a)({},e,{href:b}))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),i=n(454),o=n(447),s=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.className,a=e.badge,o=e.leftIcon,c=e.rightIcon,l=e.size,b=e.target,u=e.to,m=s()("jump-to","jump-to--"+l,n),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):"",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:m},d):r.a.createElement(i.a,{to:u,className:m},d)}},458: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.63239f49.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[217],{368:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return o})),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),i=(n(0),n(451)),o=(n(450),n(455),n(459),{last_modified_on:"2023-12-30",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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(i.b)("wrapper",Object(a.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(i.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(i.b)("inlineCode",{parentName:"p"},"Amazon SQS"),") to build a highly scalable backend."),Object(i.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(i.b)("h2",{id:"goal"},"Goal"),Object(i.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(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"We will use ",Object(i.b)("inlineCode",{parentName:"li"},"AWS Lambda")," to process events from the queue in a serverless way"),Object(i.b)("li",{parentName:"ul"},"We will use Qovery-managed backend application workers to process events from the queue")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/1.png",alt:"AWS SQS Lambda"})),Object(i.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(i.b)("p",null,"The backend application and workers servers that consume messages from the queue will be fully managed and deployed by Qovery."),Object(i.b)("p",null,"Let's get started."),Object(i.b)("h2",{id:"configure-sqs"},"Configure SQS"),Object(i.b)("p",null,"Open ",Object(i.b)("inlineCode",{parentName:"p"},"Amazon SQS")," service in AWS Console and click on ",Object(i.b)("inlineCode",{parentName:"p"},"Create Queue")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/2.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"We will use the ",Object(i.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(i.b)("inlineCode",{parentName:"p"},"Create"),"."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/3.png",alt:"AWS SQS Lambda"})),Object(i.b)("h2",{id:"create-message-producer"},"Create Message Producer"),Object(i.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(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/aws-sqs-example/blob/main/index.js"}),"here"),"."),Object(i.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(i.b)("pre",null,Object(i.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(i.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(i.b)("inlineCode",{parentName:"p"},"3000"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/4.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"Afterwards, we need to add two environment variables:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"accessKeyId")," - your AWS access key ID"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"secretAccessKey")," - your AWS secret access key")),Object(i.b)("p",null,"You can add them in ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variebles")," ",Object(i.b)("inlineCode",{parentName:"p"},"Secret")," section in your application settings:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/5.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/6.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"After all the setup is all done, click the ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy")," button - the application will be shortly deployed."),Object(i.b)("h2",{id:"create-lambda-consumers"},"Create Lambda Consumers"),Object(i.b)("p",null,"In AWS Console, open ",Object(i.b)("inlineCode",{parentName:"p"},"AWS Lambda")," panel."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/7.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"For the sake of the guide, we will use a simple ",Object(i.b)("inlineCode",{parentName:"p"},"hello-world")," lambda from AWS serverless app repository."),Object(i.b)("p",null,"Browse the app repository and pick the ",Object(i.b)("inlineCode",{parentName:"p"},"hello-world")," function as shown in the screenshot above, and deploy the function"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/8.png",alt:"AWS SQS Lambda"})),Object(i.b)("h2",{id:"create-lambda-trigger"},"Create Lambda Trigger"),Object(i.b)("p",null,"To make our Lambdas consume messages from SQS, we will need to add a ",Object(i.b)("inlineCode",{parentName:"p"},"Lambda Trigger")," in the SQS configuration."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/9.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"Click on ",Object(i.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(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/10.png",alt:"AWS SQS Lambda"})),Object(i.b)("h2",{id:"configure-permissions"},"Configure Permissions"),Object(i.b)("p",null,"Let's now grant our Lambda functions access to the SQS queue we created before."),Object(i.b)("p",null,"In our lambda view, click on ",Object(i.b)("inlineCode",{parentName:"p"},"Configure"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/11.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"Then, click on a role in ",Object(i.b)("inlineCode",{parentName:"p"},"Execution role")," to get redirected to a view where we can alter our Lambda permissions."),Object(i.b)("p",null,"In the role summary screen, click on ",Object(i.b)("inlineCode",{parentName:"p"},"Edit policy")," next to ",Object(i.b)("inlineCode",{parentName:"p"},"helloWorldrolePolicy")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/12.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"In the ",Object(i.b)("inlineCode",{parentName:"p"},"SQS")," section, grant permissions to all Read/Write options in the ",Object(i.b)("inlineCode",{parentName:"p"},"Actions")," ",Object(i.b)("inlineCode",{parentName:"p"},"Access level")," and accept the changes:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/13.png",alt:"AWS SQS Lambda"})),Object(i.b)("h2",{id:"test-lambda-as-an-sqs-consumer-flow"},"Test Lambda as an SQS Consumer Flow"),Object(i.b)("p",null,"To push messages to our SQS queue from the backend app deployed on Qovery, click on the ",Object(i.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(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/14.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"Now, in the ",Object(i.b)("inlineCode",{parentName:"p"},"Monitoring")," section of SQS in AWS Console, we will see messages received on metrics charts:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/15.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"To validate that our consumer Lambdas processed the messages, navigate to your lambda ",Object(i.b)("inlineCode",{parentName:"p"},"Monitor")," panel:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/16.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"In the ",Object(i.b)("inlineCode",{parentName:"p"},"Invocations")," chart, you'll notice that our Lambda was triggered several times by the messages sent over the SQS."),Object(i.b)("h2",{id:"conclusions"},"Conclusions"),Object(i.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},449: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 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)},m={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,i=e.originalType,o=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=b(n),d=a,p=u["".concat(o,".").concat(d)]||u[d]||m[d]||i;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 i=n.length,o=new Array(i);o[0]=d;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,o[1]=s;for(var l=2;l1?arguments[1]:void 0,n),c=o>2?arguments[2]:void 0,l=void 0===c?n:r(c,n);l>s;)t[s++]=e;return t}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),i=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),i=n.n(r),o=n(39),s=n(460),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),m=Object(r.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,u]),b&&u?i.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(b),m.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})):i.a.createElement("a",Object(a.a)({},e,{href:b}))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),i=n(456),o=n(449),s=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.className,a=e.badge,o=e.leftIcon,c=e.rightIcon,l=e.size,b=e.target,u=e.to,m=s()("jump-to","jump-to--"+l,n),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):"",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:m},d):r.a.createElement(i.a,{to:u,className:m},d)}},460: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.a2a598a6.js.LICENSE.txt b/bbedfc29.63239f49.js.LICENSE.txt similarity index 100% rename from bc592dc7.a2a598a6.js.LICENSE.txt rename to bbedfc29.63239f49.js.LICENSE.txt diff --git a/a9994e72.bdcc7cbd.js b/bbfbe73c.d5edb00f.js similarity index 93% rename from a9994e72.bdcc7cbd.js rename to bbfbe73c.d5edb00f.js index c34aeb3d46..c320835b0e 100644 --- a/a9994e72.bdcc7cbd.js +++ b/bbfbe73c.d5edb00f.js @@ -1,2 +1,2 @@ -/*! For license information please see a9994e72.bdcc7cbd.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[185],{337: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(449)),i=n(448),c=n(457),l=n(453),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},454:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),c=n(458),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}))}},457:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(454),i=n(447),c=n.n(i);n(134);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)}},458: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.d5edb00f.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[218],{369: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(451)),i=n(450),c=n(459),l=n(455),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},456:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),c=n(460),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}))}},459:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(456),i=n(449),c=n.n(i);n(134);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)}},460: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.20ddca8e.js.LICENSE.txt b/bbfbe73c.d5edb00f.js.LICENSE.txt similarity index 100% rename from bd10520b.20ddca8e.js.LICENSE.txt rename to bbfbe73c.d5edb00f.js.LICENSE.txt diff --git a/bc592dc7.a2a598a6.js b/bc592dc7.f3018ae7.js similarity index 96% rename from bc592dc7.a2a598a6.js rename to bc592dc7.f3018ae7.js index 4bf0902944..3f5603da92 100644 --- a/bc592dc7.a2a598a6.js +++ b/bc592dc7.f3018ae7.js @@ -1,2 +1,2 @@ -/*! For license information please see bc592dc7.a2a598a6.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[217],{368: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(449)),i=(a(448),a(453),a(457)),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},447: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}},452: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""}}})},453:function(e,t,a){"use strict";a(452);var r=a(0),n=a.n(r),o=a(448);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)}},454:function(e,t,a){"use strict";var r=a(1),n=a(0),o=a.n(n),i=a(39),c=a(458),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}))}},457:function(e,t,a){"use strict";var r=a(0),n=a.n(r),o=a(454),i=a(447),c=a.n(i);a(134);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)}},458: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.f3018ae7.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[219],{370: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(451)),i=(a(450),a(455),a(459)),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},449: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}},454: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""}}})},455:function(e,t,a){"use strict";a(454);var r=a(0),n=a.n(r),o=a(450);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)}},456:function(e,t,a){"use strict";var r=a(1),n=a(0),o=a.n(n),i=a(39),c=a(460),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}))}},459:function(e,t,a){"use strict";var r=a(0),n=a.n(r),o=a(456),i=a(449),c=a.n(i);a(134);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)}},460: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.031987e5.js.LICENSE.txt b/bc592dc7.f3018ae7.js.LICENSE.txt similarity index 100% rename from bdd6d8c6.031987e5.js.LICENSE.txt rename to bc592dc7.f3018ae7.js.LICENSE.txt diff --git a/bd10520b.20ddca8e.js b/bd10520b.e06c7d18.js similarity index 88% rename from bd10520b.20ddca8e.js rename to bd10520b.e06c7d18.js index ee16d271c3..da641dd97f 100644 --- a/bd10520b.20ddca8e.js +++ b/bd10520b.e06c7d18.js @@ -1,2 +1,2 @@ -/*! For license information please see bd10520b.20ddca8e.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[218],{369: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(449)),c=n(448),i=(n(457),n(453)),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},454:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),c=n(39),i=n(458),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}))}},457:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(454),c=n(447),i=n.n(c);n(134);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)}},458: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.e06c7d18.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[220],{371: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(451)),c=n(450),i=(n(459),n(455)),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},456:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),c=n(39),i=n(460),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}))}},459:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(456),c=n(449),i=n.n(c);n(134);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)}},460: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/be464708.26ad58db.js.LICENSE.txt b/bd10520b.e06c7d18.js.LICENSE.txt similarity index 100% rename from be464708.26ad58db.js.LICENSE.txt rename to bd10520b.e06c7d18.js.LICENSE.txt diff --git a/e4768112.65625a64.js b/bdd6d8c6.b6932d43.js similarity index 92% rename from e4768112.65625a64.js rename to bdd6d8c6.b6932d43.js index 92de9bf497..1c803c456a 100644 --- a/e4768112.65625a64.js +++ b/bdd6d8c6.b6932d43.js @@ -1,2 +1,2 @@ -/*! For license information please see e4768112.65625a64.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[269],{421: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(449)),c=n(456),i=(n(448),n(453)),s=(n(457),{last_modified_on:"2023-12-30",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),c=n(39),i=n(458),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}))}},455:function(e,t,n){"use strict";var a=n(459),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("&"):""}},456:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(447),n(455)),c=n.n(o);n(133);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"),"."))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(454),c=n(447),i=n.n(c);n(134);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)}},458:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},459: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.b6932d43.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[221],{372: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(451)),c=n(458),i=(n(450),n(455)),s=(n(459),{last_modified_on:"2023-12-30",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),c=n(39),i=n(460),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}))}},457:function(e,t,n){"use strict";var a=n(461),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("&"):""}},458:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(449),n(457)),c=n.n(o);n(133);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"),"."))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(456),c=n(449),i=n.n(c);n(134);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)}},460:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},461: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/c0594016.1bbc9c43.js.LICENSE.txt b/bdd6d8c6.b6932d43.js.LICENSE.txt similarity index 100% rename from c0594016.1bbc9c43.js.LICENSE.txt rename to bdd6d8c6.b6932d43.js.LICENSE.txt diff --git a/be464708.26ad58db.js b/be464708.e21b665e.js similarity index 90% rename from be464708.26ad58db.js rename to be464708.e21b665e.js index 4178df0e38..1e68fb9b03 100644 --- a/be464708.26ad58db.js +++ b/be464708.e21b665e.js @@ -1,2 +1,2 @@ -/*! For license information please see be464708.26ad58db.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[220],{371: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 b}));var r=n(1),o=n(9),a=(n(0),n(449)),c=n(456),i=n(448),l=(n(453),{last_modified_on:"2024-05-14",title:"Create Credentials",description:"Generate your GCP credentials to connect your GCP account to Qovery"}),u={id:"getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials",title:"Create Credentials",description:"Generate your GCP credentials to connect your GCP account to Qovery",source:"@site/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials.md",permalink:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials",sidebar:"docs",previous:{title:"Quickstart",permalink:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart"},next:{title:"Self-Managed Cluster",permalink:"/docs/getting-started/install-qovery/gcp/self-managed-cluster"}},s=[{value:"Generate your GCP credentials",id:"generate-your-gcp-credentials",children:[{value:"Install a new cluster on Qovery",id:"install-a-new-cluster-on-qovery",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,"This guide will help you to generate your GCP credentials to connect your GCP account to Qovery."),Object(a.b)("h2",{id:"generate-your-gcp-credentials"},"Generate your GCP credentials"),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(r.a)({parentName:"p"},{href:"https://console.cloud.google.com"}),"Connect to your GCP console"))),Object(a.b)("li",null,Object(a.b)("p",null,"Create a new ",Object(a.b)("inlineCode",{parentName:"p"},"Project")," or open an exiting one"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/gcp-credentials/gcp_project.png"}))),Object(a.b)("li",null,Object(a.b)("p",null,"Open the embedded Google shell"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/gcp-credentials/gcp_shell_1.png"}))),Object(a.b)("li",null,Object(a.b)("p",null,"Run the following command in the Google Shell to create the service account and generate the json key:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"curl https://hub.qovery.com/files/create_credentials_gcp.sh | \\\nbash -s -- $GOOGLE_CLOUD_PROJECT qovery_role qovery-service-account\n")),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"You can modify:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"the service account name by replacing ",Object(a.b)("inlineCode",{parentName:"li"},"qovery-service-account")," by the name of your choice"),Object(a.b)("li",{parentName:"ul"},"the role name by replacing ",Object(a.b)("inlineCode",{parentName:"li"},"qovery_role")," by the role name of your choice")))),Object(a.b)("li",null,Object(a.b)("p",null,"Once the script is finished, you will see the following message:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"created key [xxxx] of type [json] as [key.json] for [qovery-service-account@.iam.gserviceaccount.com]\nOperations completed. You can now download your json key to upload in Qovery\n")),Object(a.b)("p",null,"So you can download it by clicking on the ",Object(a.b)("inlineCode",{parentName:"p"},"Download")," button."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/gcp-credentials/gcp_shell_5.png"})),Object(a.b)("p",null,"And specify the name of the file ",Object(a.b)("inlineCode",{parentName:"p"},"/your/home/key.json")," and click on ",Object(a.b)("inlineCode",{parentName:"p"},"Download"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/gcp-credentials/gcp_shell_6.png"})),Object(a.b)("p",null,"That's it!")))),Object(a.b)("p",null,"Well done!! You now have your GCP ",Object(a.b)("inlineCode",{parentName:"p"},"JSON credentials key"),"; It is time to connect Qovery to your GCP account."),Object(a.b)("h3",{id:"install-a-new-cluster-on-qovery"},"Install a new cluster on Qovery"),Object(a.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(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"this documentation")," to create a new cluster on your organization."))}b.isMDXComponent=!0},447: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},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,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,f=p["".concat(c,".").concat(d)]||p[d]||b[d]||a;return n?o.a.createElement(f,i({ref:t},u,{components:n})):o.a.createElement(f,i({ref:t},u))}));function f(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 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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(447),n(455)),c=n.n(a);n(133);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),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"),"."))}},459: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 be464708.e21b665e.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[222],{373: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 b}));var r=n(1),o=n(9),a=(n(0),n(451)),c=n(458),i=n(450),l=(n(455),{last_modified_on:"2024-05-14",title:"Create Credentials",description:"Generate your GCP credentials to connect your GCP account to Qovery"}),u={id:"getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials",title:"Create Credentials",description:"Generate your GCP credentials to connect your GCP account to Qovery",source:"@site/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials.md",permalink:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials",sidebar:"docs",previous:{title:"Quickstart",permalink:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart"},next:{title:"Self-Managed Cluster",permalink:"/docs/getting-started/install-qovery/gcp/self-managed-cluster"}},s=[{value:"Generate your GCP credentials",id:"generate-your-gcp-credentials",children:[{value:"Install a new cluster on Qovery",id:"install-a-new-cluster-on-qovery",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,"This guide will help you to generate your GCP credentials to connect your GCP account to Qovery."),Object(a.b)("h2",{id:"generate-your-gcp-credentials"},"Generate your GCP credentials"),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(r.a)({parentName:"p"},{href:"https://console.cloud.google.com"}),"Connect to your GCP console"))),Object(a.b)("li",null,Object(a.b)("p",null,"Create a new ",Object(a.b)("inlineCode",{parentName:"p"},"Project")," or open an exiting one"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/gcp-credentials/gcp_project.png"}))),Object(a.b)("li",null,Object(a.b)("p",null,"Open the embedded Google shell"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/gcp-credentials/gcp_shell_1.png"}))),Object(a.b)("li",null,Object(a.b)("p",null,"Run the following command in the Google Shell to create the service account and generate the json key:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-bash"}),"curl https://hub.qovery.com/files/create_credentials_gcp.sh | \\\nbash -s -- $GOOGLE_CLOUD_PROJECT qovery_role qovery-service-account\n")),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"You can modify:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"the service account name by replacing ",Object(a.b)("inlineCode",{parentName:"li"},"qovery-service-account")," by the name of your choice"),Object(a.b)("li",{parentName:"ul"},"the role name by replacing ",Object(a.b)("inlineCode",{parentName:"li"},"qovery_role")," by the role name of your choice")))),Object(a.b)("li",null,Object(a.b)("p",null,"Once the script is finished, you will see the following message:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{}),"created key [xxxx] of type [json] as [key.json] for [qovery-service-account@.iam.gserviceaccount.com]\nOperations completed. You can now download your json key to upload in Qovery\n")),Object(a.b)("p",null,"So you can download it by clicking on the ",Object(a.b)("inlineCode",{parentName:"p"},"Download")," button."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/gcp-credentials/gcp_shell_5.png"})),Object(a.b)("p",null,"And specify the name of the file ",Object(a.b)("inlineCode",{parentName:"p"},"/your/home/key.json")," and click on ",Object(a.b)("inlineCode",{parentName:"p"},"Download"),"."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/gcp-credentials/gcp_shell_6.png"})),Object(a.b)("p",null,"That's it!")))),Object(a.b)("p",null,"Well done!! You now have your GCP ",Object(a.b)("inlineCode",{parentName:"p"},"JSON credentials key"),"; It is time to connect Qovery to your GCP account."),Object(a.b)("h3",{id:"install-a-new-cluster-on-qovery"},"Install a new cluster on Qovery"),Object(a.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(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#creating-a-cluster"}),"this documentation")," to create a new cluster on your organization."))}b.isMDXComponent=!0},449: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},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,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),d=r,f=p["".concat(c,".").concat(d)]||p[d]||b[d]||a;return n?o.a.createElement(f,i({ref:t},u,{components:n})):o.a.createElement(f,i({ref:t},u))}));function f(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 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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(449),n(457)),c=n.n(a);n(133);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),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"),"."))}},461: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.bf36c9cd.js.LICENSE.txt b/be464708.e21b665e.js.LICENSE.txt similarity index 100% rename from c0ab55e0.bf36c9cd.js.LICENSE.txt rename to be464708.e21b665e.js.LICENSE.txt diff --git a/bf22200e.1732a05d.js b/bf22200e.1732a05d.js deleted file mode 100644 index 7cacd30aad..0000000000 --- a/bf22200e.1732a05d.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[221],{372:function(t){t.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"type-tutorial","name":"type: tutorial","count":42,"permalink":"/guides/tags/type-tutorial"}')}}]); \ No newline at end of file diff --git a/bf22200e.7c430e12.js b/bf22200e.7c430e12.js new file mode 100644 index 0000000000..17279082ef --- /dev/null +++ b/bf22200e.7c430e12.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[223],{374:function(t){t.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"type-tutorial","name":"type: tutorial","count":43,"permalink":"/guides/tags/type-tutorial"}')}}]); \ No newline at end of file diff --git a/c0594016.1bbc9c43.js b/c0594016.93d40c85.js similarity index 90% rename from c0594016.1bbc9c43.js rename to c0594016.93d40c85.js index c56ab7e257..85fb02e1f9 100644 --- a/c0594016.1bbc9c43.js +++ b/c0594016.93d40c85.js @@ -1,2 +1,2 @@ -/*! For license information please see c0594016.1bbc9c43.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[222],{373: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(449)),i=n(456),c=n(453),u=(n(448),{last_modified_on:"2024-02-27",$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://discuss.qovery.com/"}),"find us on our forum")," or on Intercom depending on your support plan."))}p.isMDXComponent=!0},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(447),n(455)),i=n.n(a);n(133);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"),"."))}},459: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.93d40c85.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[224],{375: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(451)),i=n(458),c=n(455),u=(n(450),{last_modified_on:"2024-02-27",$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://discuss.qovery.com/"}),"find us on our forum")," or on Intercom depending on your support plan."))}p.isMDXComponent=!0},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(449),n(457)),i=n.n(a);n(133);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"),"."))}},461: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.156363da.js.LICENSE.txt b/c0594016.93d40c85.js.LICENSE.txt similarity index 100% rename from c24a85bb.156363da.js.LICENSE.txt rename to c0594016.93d40c85.js.LICENSE.txt diff --git a/c0ab55e0.bf36c9cd.js b/c0ab55e0.dc295627.js similarity index 95% rename from c0ab55e0.bf36c9cd.js rename to c0ab55e0.dc295627.js index 9ece2d994a..a9c494ee21 100644 --- a/c0ab55e0.bf36c9cd.js +++ b/c0ab55e0.dc295627.js @@ -1,2 +1,2 @@ -/*! For license information please see c0ab55e0.bf36c9cd.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[223],{374: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),i=n(9),r=(n(0),n(449)),o=(n(457),n(448)),c=(n(453),{last_modified_on:"2024-05-02",$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:"7 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:"Deploy a service account with Helm",id:"deploy-a-service-account-with-helm",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 p(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 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 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:"deploy-a-service-account-with-helm"},"Deploy a service account with Helm"),Object(r.b)("p",null,"Qovery provides a simple Helm chart to deploy a service account on your Kubernetes cluster in a specific environment (Kubernetes namespace). "),Object(r.b)("p",null,"Start to create a new service, with an Helm chart:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/create_sa.png",alt:"Create Service Account"})),Object(r.b)("p",null,"Then configure the Helm chart with the following values:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/helm_sa_1.png",alt:"Helm chart"})),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Helm source: ",Object(r.b)("inlineCode",{parentName:"li"},"Helm repository")),Object(r.b)("li",{parentName:"ul"},"Git repository: ",Object(r.b)("inlineCode",{parentName:"li"},"Qovery Service Account Helper")),Object(r.b)("li",{parentName:"ul"},"Chart name: ",Object(r.b)("inlineCode",{parentName:"li"},"qovery-sa-helper")),Object(r.b)("li",{parentName:"ul"},"Version: ",Object(r.b)("inlineCode",{parentName:"li"},"0.1.0"))),Object(r.b)("p",null,"Create a new help repository on phase 3, and fill the chart info:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/set-helm-repo.png",alt:"Helm chart"})),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Repository name: ",Object(r.b)("inlineCode",{parentName:"li"},"Qovery Service Account Helper")),Object(r.b)("li",{parentName:"ul"},"Kind: HTTPS"),Object(r.b)("li",{parentName:"ul"},"Repository url: ",Object(r.b)("inlineCode",{parentName:"li"},"https://qovery.github.io/create_service_account/"))),Object(r.b)("p",null,"Then click on ",Object(r.b)("inlineCode",{parentName:"p"},"Create"),", and the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button."),Object(r.b)("p",null,"On the values override file, we do not need to override anything, so select ",Object(r.b)("inlineCode",{parentName:"p"},"None"),", and then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/helm_sa_2.png",alt:"Helm chart"})),Object(r.b)("p",null,"We then have to add 2 override arguments:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},Object(r.b)("inlineCode",{parentName:"li"},"serviceAccount.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:"ol"},Object(r.b)("inlineCode",{parentName:"li"},"awsRoleArn"),": the ARN of the role you have created")),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/helm_sa_3.png",alt:"Helm chart"})),Object(r.b)("p",null,"Then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button."),Object(r.b)("p",null,"You can finally Create and Deploy it. If you look at the logs, you should see something like:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/helm_sa_logs.png",alt:"Helm chart"})),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 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!"))}p.isMDXComponent=!0},447: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},p=function(e){var t=b(e.components);return i.a.createElement(s.Provider,{value:t},e.children)},u={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"]),p=b(n),m=a,d=p["".concat(o,".").concat(m)]||p[m]||u[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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),i=n.n(a),r=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),i=n(0),r=n.n(i),o=n(39),c=n(458),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,b=n||l,p=Object(c.a)(b),u=Object(i.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!m&&p&&window.docusaurus.prefetch(b),function(){m&&t&&t.disconnect()}}),[b,m,p]),b&&p?r.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})):r.a.createElement("a",Object(a.a)({},e,{href:b}))}},457:function(e,t,n){"use strict";var a=n(0),i=n.n(a),r=n(454),o=n(447),c=n.n(o);n(134);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=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 b?i.a.createElement("a",{href:p,target:b,className:u},m):i.a.createElement(r.a,{to:p,className:u},m)}},458: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.dc295627.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[225],{376: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),i=n(9),r=(n(0),n(451)),o=(n(459),n(450)),c=(n(455),{last_modified_on:"2024-05-02",$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:"7 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:"Deploy a service account with Helm",id:"deploy-a-service-account-with-helm",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 p(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 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 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:"deploy-a-service-account-with-helm"},"Deploy a service account with Helm"),Object(r.b)("p",null,"Qovery provides a simple Helm chart to deploy a service account on your Kubernetes cluster in a specific environment (Kubernetes namespace). "),Object(r.b)("p",null,"Start to create a new service, with an Helm chart:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/create_sa.png",alt:"Create Service Account"})),Object(r.b)("p",null,"Then configure the Helm chart with the following values:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/helm_sa_1.png",alt:"Helm chart"})),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Helm source: ",Object(r.b)("inlineCode",{parentName:"li"},"Helm repository")),Object(r.b)("li",{parentName:"ul"},"Git repository: ",Object(r.b)("inlineCode",{parentName:"li"},"Qovery Service Account Helper")),Object(r.b)("li",{parentName:"ul"},"Chart name: ",Object(r.b)("inlineCode",{parentName:"li"},"qovery-sa-helper")),Object(r.b)("li",{parentName:"ul"},"Version: ",Object(r.b)("inlineCode",{parentName:"li"},"0.1.0"))),Object(r.b)("p",null,"Create a new help repository on phase 3, and fill the chart info:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/set-helm-repo.png",alt:"Helm chart"})),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Repository name: ",Object(r.b)("inlineCode",{parentName:"li"},"Qovery Service Account Helper")),Object(r.b)("li",{parentName:"ul"},"Kind: HTTPS"),Object(r.b)("li",{parentName:"ul"},"Repository url: ",Object(r.b)("inlineCode",{parentName:"li"},"https://qovery.github.io/create_service_account/"))),Object(r.b)("p",null,"Then click on ",Object(r.b)("inlineCode",{parentName:"p"},"Create"),", and the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button."),Object(r.b)("p",null,"On the values override file, we do not need to override anything, so select ",Object(r.b)("inlineCode",{parentName:"p"},"None"),", and then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button."),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/helm_sa_2.png",alt:"Helm chart"})),Object(r.b)("p",null,"We then have to add 2 override arguments:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},Object(r.b)("inlineCode",{parentName:"li"},"serviceAccount.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:"ol"},Object(r.b)("inlineCode",{parentName:"li"},"awsRoleArn"),": the ARN of the role you have created")),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/helm_sa_3.png",alt:"Helm chart"})),Object(r.b)("p",null,"Then click on the ",Object(r.b)("inlineCode",{parentName:"p"},"Continue")," button."),Object(r.b)("p",null,"You can finally Create and Deploy it. If you look at the logs, you should see something like:"),Object(r.b)("p",{Valign:"center"},Object(r.b)("img",{src:"/img/aws-iam-assume-role/helm_sa_logs.png",alt:"Helm chart"})),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 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!"))}p.isMDXComponent=!0},449: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},p=function(e){var t=b(e.components);return i.a.createElement(s.Provider,{value:t},e.children)},u={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"]),p=b(n),m=a,d=p["".concat(o,".").concat(m)]||p[m]||u[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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),i=n.n(a),r=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),i=n(0),r=n.n(i),o=n(39),c=n(460),l=n(20),s=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,b=n||l,p=Object(c.a)(b),u=Object(i.useRef)(!1),m=s.a.canUseIntersectionObserver;return Object(i.useEffect)((function(){return!m&&p&&window.docusaurus.prefetch(b),function(){m&&t&&t.disconnect()}}),[b,m,p]),b&&p?r.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})):r.a.createElement("a",Object(a.a)({},e,{href:b}))}},459:function(e,t,n){"use strict";var a=n(0),i=n.n(a),r=n(456),o=n(449),c=n.n(o);n(134);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=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 b?i.a.createElement("a",{href:p,target:b,className:u},m):i.a.createElement(r.a,{to:p,className:u},m)}},460: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.9660767a.js.LICENSE.txt b/c0ab55e0.dc295627.js.LICENSE.txt similarity index 100% rename from c3f02c14.9660767a.js.LICENSE.txt rename to c0ab55e0.dc295627.js.LICENSE.txt diff --git a/c24a85bb.156363da.js b/c24a85bb.06ac3e5b.js similarity index 89% rename from c24a85bb.156363da.js rename to c24a85bb.06ac3e5b.js index b5120820ee..07b4a2c6ee 100644 --- a/c24a85bb.156363da.js +++ b/c24a85bb.06ac3e5b.js @@ -1,2 +1,2 @@ -/*! For license information please see c24a85bb.156363da.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[224],{375: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(449)),i=(n(456),n(453),n(448),{last_modified_on:"2024-01-10",$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"]}),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:"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"}},l=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",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)("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(r.a)({parentName:"p"},{href:"https://helm.sh"}),"official website"),"."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"You can find ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/"}),"here")," the official documentation on how to deploy a helm chart with Qovery. Below you have two real examples."),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)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Deploy Kubecost"),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost/"}),"How to deploy Kubecost helm chart"))),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Deploy Datadog"),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/"}),"How to deploy Datadog helm chart"))))),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"),"."))}s.isMDXComponent=!0},447: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)}},f=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),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 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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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 c24a85bb.06ac3e5b.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[226],{377: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(451)),i=(n(458),n(455),n(450),{last_modified_on:"2024-01-10",$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"]}),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:"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"}},l=[{value:"Resources",id:"resources",children:[]},{value:"Q&A",id:"qa",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)("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(r.a)({parentName:"p"},{href:"https://helm.sh"}),"official website"),"."),Object(o.b)("h2",{id:"resources"},"Resources"),Object(o.b)("p",null,"You can find ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/"}),"here")," the official documentation on how to deploy a helm chart with Qovery. Below you have two real examples."),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)("tbody",{parentName:"table"},Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Deploy Kubecost"),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost/"}),"How to deploy Kubecost helm chart"))),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Deploy Datadog"),Object(o.b)("td",Object(r.a)({parentName:"tr"},{align:null}),Object(o.b)("a",Object(r.a)({parentName:"td"},{href:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/"}),"How to deploy Datadog helm chart"))))),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"),"."))}s.isMDXComponent=!0},449: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)}},f=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),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 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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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/c4f5d8e4.1ca2718e.js.LICENSE.txt b/c24a85bb.06ac3e5b.js.LICENSE.txt similarity index 100% rename from c4f5d8e4.1ca2718e.js.LICENSE.txt rename to c24a85bb.06ac3e5b.js.LICENSE.txt diff --git a/c3f02c14.9660767a.js b/c3f02c14.38b61408.js similarity index 92% rename from c3f02c14.9660767a.js rename to c3f02c14.38b61408.js index 18fe182ad7..a91a28543b 100644 --- a/c3f02c14.9660767a.js +++ b/c3f02c14.38b61408.js @@ -1,2 +1,2 @@ -/*! For license information please see c3f02c14.9660767a.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[225],{376: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(449)),c=r(448),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},447: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.38b61408.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[227],{378: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(451)),c=r(450),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},449: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.a051c92d.js.LICENSE.txt b/c3f02c14.38b61408.js.LICENSE.txt similarity index 100% rename from c7bfb1d3.a051c92d.js.LICENSE.txt rename to c3f02c14.38b61408.js.LICENSE.txt diff --git a/c4f5d8e4.1ca2718e.js b/c4f5d8e4.5a6c4d83.js similarity index 92% rename from c4f5d8e4.1ca2718e.js rename to c4f5d8e4.5a6c4d83.js index 3f196c282e..d1dcf6ea31 100644 --- a/c4f5d8e4.1ca2718e.js +++ b/c4f5d8e4.5a6c4d83.js @@ -1,2 +1,2 @@ -/*! For license information please see c4f5d8e4.1ca2718e.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[226],{377:function(e,t,a){"use strict";a.r(t);var n=a(0),r=a.n(n),i=a(474),l=a(471),o=a(586);Object(i.a)("h2");t.default=function(){return r.a.createElement(l.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 a DevOps Automation Platform that eliminates your DevOps hiring needs. Provision and maintain a secure and compliant infrastructure in hours - not months!.",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://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"))))))))}},447: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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),c.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||l)&&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,l),r.a.createElement("br",null))))},R=a(486),q=a(487),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),c=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||c,y=s+Object(_.a)(E),w=Object(_.a)(n),N=Object(F.h)(),k=N?"https://docs.qovery.com"+(N.pathname.endsWith("/")?N.pathname:N.pathname+"/"):null;return r.a.createElement(q.a,null,r.a.createElement(R.a,null,r.a.createElement(l.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(i.a,null),r.a.createElement(S,null),r.a.createElement("div",{className:"main-wrapper"},m),!d&&r.a.createElement(Q,null)))}},474:function(e,t,a){"use strict";var n=a(9),r=a(0),i=a.n(r),l=a(447),o=a.n(l),c=a(460),s=(a(139),a(140)),m=a.n(s);t.a=function(e){return function(t){var a,r=t.id,l=Object(n.a)(t,["id"]),s=Object(c.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?i.a.createElement(e,l,i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:o()("anchor",(a={},a[m.a.enhancedAnchor]=!p,a)),id:r}),i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"hash-link",href:"#"+r,title:"Direct link to heading"},"#"),l.children):i.a.createElement(e,l)}}},478:function(e,t,a){"use strict";var n=a(0),r=Object(n.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=r},503:function(e,t){var a,n,r=e.exports={};function i(){throw new Error("setTimeout has not been defined")}function l(){throw new Error("clearTimeout has not been defined")}function o(e){if(a===setTimeout)return setTimeout(e,0);if((a===i||!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:i}catch(e){a=i}try{n="function"==typeof clearTimeout?clearTimeout:l}catch(e){n=l}}();var c,s=[],m=!1,u=-1;function d(){m&&c&&(m=!1,c.length?s=c.concat(s):u=-1,s.length&&f())}function f(){if(!m){var e=o(d);m=!0;for(var t=s.length;t;){for(c=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(503))},580:function(e,t,a){var n;function r(e){function a(){if(a.enabled){var e=a,r=+new Date,i=r-(n||r);e.diff=i,e.prev=n,e.curr=r,n=r;for(var l=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 l=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*l;case"days":case"day":case"d":return l*i;case"hours":case"hour":case"hrs":case"hr":case"h":return l*r;case"minutes":case"minute":case"mins":case"min":case"m":return l*n;case"seconds":case"second":case"secs":case"sec":case"s":return l*a;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return l;default:return}}(e);if("number"===c&&!1===isNaN(e))return t.long?l(o=e,i,"day")||l(o,r,"hour")||l(o,n,"minute")||l(o,a,"second")||o+" ms":function(e){if(e>=i)return Math.round(e/i)+"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))}},582: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}))}},586:function(e,t,a){"use strict";a(472),a(473);var n=a(0),r=a.n(n),i=a(447),l=a.n(i),o=(a(58),a(21),a(578)),c=a.n(o),s=a(582),m=function(e){return new Promise((function(t,a){return c()(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 i="https://qovery.us4.list-manage.com/subscribe/post-json?u=3c76e7a2087d5bc4020348c46&id=63bd993879";arguments.length<3&&"string"==typeof t?i=t:"string"==typeof a&&(i=a);var l="&EMAIL="+r+u(t),o=""+i+l;return m(o)};a(152),t.a=function(e){var t,a=e.block,i=e.buttonClass,o=e.center,c=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],w=E[1],N=Object(n.useState)("Could not subscribe :("),k=N[0],_=N[1];return r.a.createElement("div",{className:l()("mailing-list",(t={"mailing-list--block":a,"mailing-list--center":o},t["mailing-list--"+m]=m,t))},!1!==c&&r.a.createElement("div",{className:"mailing-list--description"},c),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&&w(!1)):(w(!0),e.msg.includes(p+" is already subscribed")?_("This email is already subscribed to the newsletter"):_("Could not subscribe :("))})).catch((function(e){w(!0)}))}(e)},className:l()("mailing-list--form")},r.a.createElement("input",{onChange:function(e){return h(e.target.value)},className:l()("input","input--"+m),name:"email",placeholder:"you@email.com",type:"email",style:{width:u}}),r.a.createElement("button",{className:l()("button","button--"+(i||"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.5a6c4d83.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[228],{379:function(e,t,a){"use strict";a.r(t);var n=a(0),r=a.n(n),i=a(476),l=a(473),o=a(588);Object(i.a)("h2");t.default=function(){return r.a.createElement(l.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 a DevOps Automation Platform that eliminates your DevOps hiring needs. Provision and maintain a secure and compliant infrastructure in hours - not months!.",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://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"))))))))}},449: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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),c.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||l)&&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,l),r.a.createElement("br",null))))},R=a(488),q=a(489),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),c=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||c,y=s+Object(_.a)(E),w=Object(_.a)(n),N=Object(F.h)(),k=N?"https://docs.qovery.com"+(N.pathname.endsWith("/")?N.pathname:N.pathname+"/"):null;return r.a.createElement(q.a,null,r.a.createElement(R.a,null,r.a.createElement(l.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(i.a,null),r.a.createElement(S,null),r.a.createElement("div",{className:"main-wrapper"},m),!d&&r.a.createElement(Q,null)))}},476:function(e,t,a){"use strict";var n=a(9),r=a(0),i=a.n(r),l=a(449),o=a.n(l),c=a(462),s=(a(139),a(140)),m=a.n(s);t.a=function(e){return function(t){var a,r=t.id,l=Object(n.a)(t,["id"]),s=Object(c.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?i.a.createElement(e,l,i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:o()("anchor",(a={},a[m.a.enhancedAnchor]=!p,a)),id:r}),i.a.createElement("a",{"aria-hidden":"true",tabIndex:"-1",className:"hash-link",href:"#"+r,title:"Direct link to heading"},"#"),l.children):i.a.createElement(e,l)}}},480:function(e,t,a){"use strict";var n=a(0),r=Object(n.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=r},505:function(e,t){var a,n,r=e.exports={};function i(){throw new Error("setTimeout has not been defined")}function l(){throw new Error("clearTimeout has not been defined")}function o(e){if(a===setTimeout)return setTimeout(e,0);if((a===i||!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:i}catch(e){a=i}try{n="function"==typeof clearTimeout?clearTimeout:l}catch(e){n=l}}();var c,s=[],m=!1,u=-1;function d(){m&&c&&(m=!1,c.length?s=c.concat(s):u=-1,s.length&&f())}function f(){if(!m){var e=o(d);m=!0;for(var t=s.length;t;){for(c=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(505))},582:function(e,t,a){var n;function r(e){function a(){if(a.enabled){var e=a,r=+new Date,i=r-(n||r);e.diff=i,e.prev=n,e.curr=r,n=r;for(var l=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 l=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*l;case"days":case"day":case"d":return l*i;case"hours":case"hour":case"hrs":case"hr":case"h":return l*r;case"minutes":case"minute":case"mins":case"min":case"m":return l*n;case"seconds":case"second":case"secs":case"sec":case"s":return l*a;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return l;default:return}}(e);if("number"===c&&!1===isNaN(e))return t.long?l(o=e,i,"day")||l(o,r,"hour")||l(o,n,"minute")||l(o,a,"second")||o+" ms":function(e){if(e>=i)return Math.round(e/i)+"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))}},584: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}))}},588:function(e,t,a){"use strict";a(474),a(475);var n=a(0),r=a.n(n),i=a(449),l=a.n(i),o=(a(58),a(21),a(580)),c=a.n(o),s=a(584),m=function(e){return new Promise((function(t,a){return c()(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 i="https://qovery.us4.list-manage.com/subscribe/post-json?u=3c76e7a2087d5bc4020348c46&id=63bd993879";arguments.length<3&&"string"==typeof t?i=t:"string"==typeof a&&(i=a);var l="&EMAIL="+r+u(t),o=""+i+l;return m(o)};a(152),t.a=function(e){var t,a=e.block,i=e.buttonClass,o=e.center,c=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],w=E[1],N=Object(n.useState)("Could not subscribe :("),k=N[0],_=N[1];return r.a.createElement("div",{className:l()("mailing-list",(t={"mailing-list--block":a,"mailing-list--center":o},t["mailing-list--"+m]=m,t))},!1!==c&&r.a.createElement("div",{className:"mailing-list--description"},c),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&&w(!1)):(w(!0),e.msg.includes(p+" is already subscribed")?_("This email is already subscribed to the newsletter"):_("Could not subscribe :("))})).catch((function(e){w(!0)}))}(e)},className:l()("mailing-list--form")},r.a.createElement("input",{onChange:function(e){return h(e.target.value)},className:l()("input","input--"+m),name:"email",placeholder:"you@email.com",type:"email",style:{width:u}}),r.a.createElement("button",{className:l()("button","button--"+(i||"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.276e6f38.js.LICENSE.txt b/c4f5d8e4.5a6c4d83.js.LICENSE.txt similarity index 100% rename from c8223350.276e6f38.js.LICENSE.txt rename to c4f5d8e4.5a6c4d83.js.LICENSE.txt diff --git a/c536ba8c.2ccc6ebe.js b/c536ba8c.31811bc3.js similarity index 96% rename from c536ba8c.2ccc6ebe.js rename to c536ba8c.31811bc3.js index 6edd0b2a56..c2b5777908 100644 --- a/c536ba8c.2ccc6ebe.js +++ b/c536ba8c.31811bc3.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[227],{378: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(449)),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},449: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)}}),n(74)("find")},465:function(t,e,n){"use strict";var r=n(8),o=n(510),i=n(55);n(56)("search",1,(function(t,e,n,u){return[function(n){var r=t(this),o=null==n?void 0:n[e];return void 0!==o?o.call(n,r):new RegExp(n)[e](String(r))},function(t){var e=u(n,t,this);if(e.done)return e.value;var a=r(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}]}))},471:function(t,e,n){"use strict";n(481);var r=n(0),o=n.n(r),i=n(482),u=n(470),a=n(1),c=(n(472),n(473),n(483),n(454)),l=n(484),f=n(466),s=n.n(f),p=n(485),v=n.n(p),d=n(460),h=n(447),y=n.n(h),g=n(135),m=n.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,n=Date.parse(e.date),r=new Date,o=Math.abs(r-n),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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),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=n(486),W=n(487),U=n(3);n(138);e.a=function(t){var e=Object(d.a)().siteConfig,n=void 0===e?{}:e,r=n.favicon,a=(n.tagline,n.title),c=n.themeConfig.image,l=n.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)(r),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}),r&&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)))}},474:function(t,e,n){"use strict";var r=n(9),o=n(0),i=n.n(o),u=n(447),a=n.n(u),c=n(460),l=(n(139),n(140)),f=n.n(l);e.a=function(t){return function(e){var n,o=e.id,u=Object(r.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",(n={},n[f.a.enhancedAnchor]=!d,n)),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)}}},475:function(t,e,n){(function(t,r){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]",A="[object Float32Array]",j="[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,nt=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,rt=/\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]",At="[A-Z\\xc0-\\xd6\\xd8-\\xde]",jt="(?:"+Dt+"|"+_t+")",xt="(?:"+At+"|"+_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([At+"?"+Dt+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?="+[ht,At,"$"].join("|")+")",xt+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?="+[ht,At+jt,"$"].join("|")+")",At+"?"+jt+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?",At+"+(?:['\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[A]=Wt[j]=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[A]=Ut[j]=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 r&&r&&!r.nodeType&&r,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,ne=Yt&&Yt.isRegExp,re=Yt&&Yt.isSet,oe=Yt&&Yt.isTypedArray;function ie(t,e,n){switch(n.length){case 0:return t.call(e);case 1:return t.call(e,n[0]);case 2:return t.call(e,n[0],n[1]);case 3:return t.call(e,n[0],n[1],n[2])}return t.apply(e,n)}function ue(t,e,n,r){for(var o=-1,i=null==t?0:t.length;++o-1}function pe(t,e,n){for(var r=-1,o=null==t?0:t.length;++r-1;);return n}function Ie(t,e){for(var n=t.length;n--&&be(e,t[n],0)>-1;);return n}function Re(t,e){for(var n=t.length,r=0;n--;)t[n]===e&&++r;return r}var Be=je({"\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=je({"&":"&","<":"<",">":">",'"':""","'":"'"});function Te(t){return"\\"+zt[t]}function Me(t){return Bt.test(t)}function We(t){var e=-1,n=Array(t.size);return t.forEach((function(t,r){n[++e]=[r,t]})),n}function Ue(t,e){return function(n){return t(e(n))}}function ze(t,e){for(var n=-1,r=t.length,o=0,i=[];++n",""":'"',"'":"'"});var Qe=function t(e){var n,r=(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=r.prototype,_t=vt.prototype,bt=ht.prototype,Et=e["__core-js_shared__"],wt=_t.toString,Ft=bt.hasOwnProperty,At=0,jt=(n=/[^.]+$/.exec(Et&&Et.keys&&Et.keys.IE_PROTO||""))?"Symbol(src)_1."+n:"",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,je=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,tn=ht.getOwnPropertySymbols,en=Ct?Ct.isBuffer:void 0,nn=e.isFinite,rn=Dt.join,on=Ue(ht.keys,ht),un=dt.max,an=dt.min,cn=o.now,ln=e.parseInt,fn=dt.random,sn=Dt.reverse,pn=ti(e,"DataView"),vn=ti(e,"Map"),dn=ti(e,"Promise"),hn=ti(e,"Set"),yn=ti(e,"WeakMap"),gn=ti(ht,"create"),mn=yn&&new yn,Dn={},_n=xi(pn),bn=xi(vn),En=xi(dn),wn=xi(hn),Fn=xi(yn),An=It?It.prototype:void 0,jn=An?An.valueOf:void 0,xn=An?An.toString:void 0;function On(t){if(qu(t)&&!Pu(t)&&!(t instanceof Nn)){if(t instanceof Cn)return t;if(Ft.call(t,"__wrapped__"))return Oi(t)}return new Cn(t)}var Sn=function(){function t(){}return function(e){if(!$u(e))return{};if(Vt)return Vt(e);t.prototype=e;var n=new t;return t.prototype=void 0,n}}();function kn(){}function Cn(t,e){this.__wrapped__=t,this.__actions__=[],this.__chain__=!!e,this.__index__=0,this.__values__=void 0}function Nn(t){this.__wrapped__=t,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Pn(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e=e?t:e)),t}function Zn(t,e,n,r,o,i){var u,a=1&e,l=2&e,p=4&e;if(n&&(u=o?n(t,r,o,i):n(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,n=new t.constructor(e);e&&"string"==typeof t[0]&&Ft.call(t,"index")&&(n.index=t.index,n.input=t.input);return n}(t),!a)return mo(t,u)}else{var P=ri(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,ni(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,Vn(u,t))}else{if(!Ut[P])return o?t:{};u=function(t,e,n){var r=t.constructor;switch(e){case w:return po(t);case f:case s:return new r(+t);case F:return function(t,e){var n=e?po(t.buffer):t.buffer;return new t.constructor(n,t.byteOffset,t.byteLength)}(t,n);case A:case j:case x:case O:case S:case k:case"[object Uint8ClampedArray]":case C:case N:return vo(t,n);case h:return new r;case y:case _:return new r(t);case m:return function(t){var e=new t.constructor(t.source,rt.exec(t));return e.lastIndex=t.lastIndex,e}(t);case D:return new r;case b:return o=t,jn?ht(jn.call(o)):{}}var o}(t,P,a)}}i||(i=new Ln);var R=i.get(t);if(R)return R;i.set(t,u),Ju(t)?t.forEach((function(r){u.add(Zn(r,e,n,r,t,i))})):Gu(t)&&t.forEach((function(r,o){u.set(o,Zn(r,e,n,o,t,i))}));var B=E?void 0:(p?l?Ho:Vo:l?ba:_a)(t);return ae(B||t,(function(r,o){B&&(r=t[o=r]),$n(u,o,Zn(r,e,n,o,t,i))})),u}function Kn(t,e,n){var r=n.length;if(null==t)return!r;for(t=ht(t);r--;){var o=n[r],i=e[o],u=t[o];if(void 0===u&&!(o in t)||!i(u))return!1}return!0}function Yn(t,e,n){if("function"!=typeof t)throw new mt(i);return _i((function(){t.apply(void 0,n)}),e)}function Xn(t,e,n,r){var o=-1,i=se,u=!0,a=t.length,c=[],l=e.length;if(!a)return c;n&&(e=ve(e,ke(n))),r?(i=pe,u=!1):e.length>=200&&(i=Ne,u=!1,e=new Bn(e));t:for(;++o-1},In.prototype.set=function(t,e){var n=this.__data__,r=qn(n,t);return r<0?(++this.size,n.push([t,e])):n[r][1]=e,this},Rn.prototype.clear=function(){this.size=0,this.__data__={hash:new Pn,map:new(vn||In),string:new Pn}},Rn.prototype.delete=function(t){var e=Yo(this,t).delete(t);return this.size-=e?1:0,e},Rn.prototype.get=function(t){return Yo(this,t).get(t)},Rn.prototype.has=function(t){return Yo(this,t).has(t)},Rn.prototype.set=function(t,e){var n=Yo(this,t),r=n.size;return n.set(t,e),this.size+=n.size==r?0:1,this},Bn.prototype.add=Bn.prototype.push=function(t){return this.__data__.set(t,"__lodash_hash_undefined__"),this},Bn.prototype.has=function(t){return this.__data__.has(t)},Ln.prototype.clear=function(){this.__data__=new In,this.size=0},Ln.prototype.delete=function(t){var e=this.__data__,n=e.delete(t);return this.size=e.size,n},Ln.prototype.get=function(t){return this.__data__.get(t)},Ln.prototype.has=function(t){return this.__data__.has(t)},Ln.prototype.set=function(t,e){var n=this.__data__;if(n instanceof In){var r=n.__data__;if(!vn||r.length<199)return r.push([t,e]),this.size=++n.size,this;n=this.__data__=new Rn(r)}return n.set(t,e),this.size=n.size,this};var tr=Eo(cr),er=Eo(lr,!0);function nr(t,e){var n=!0;return tr(t,(function(t,r,o){return n=!!e(t,r,o)})),n}function rr(t,e,n){for(var r=-1,o=t.length;++r0&&n(a)?e>1?ir(a,e-1,n,r,o):de(o,a):r||(o[o.length]=a)}return o}var ur=wo(),ar=wo(!0);function cr(t,e){return t&&ur(t,e,_a)}function lr(t,e){return t&&ar(t,e,_a)}function fr(t,e){return fe(e,(function(e){return Wu(t[e])}))}function sr(t,e){for(var n=0,r=(e=ao(e,t)).length;null!=t&&ne}function hr(t,e){return null!=t&&Ft.call(t,e)}function yr(t,e){return null!=t&&e in ht(t)}function gr(t,e,n){for(var o=n?pe:se,i=t[0].length,u=t.length,a=u,c=r(u),l=1/0,f=[];a--;){var s=t[a];a&&e&&(s=ve(s,ke(e))),l=an(s.length,l),c[a]=!n&&(e||i>=120&&s.length>=120)?new Bn(a&&s):void 0}s=t[0];var p=-1,v=c[0];t:for(;++p=a)return c;var l=n[r];return c*("desc"==l?-1:1)}}return t.index-e.index}(t,e,n)}))}function Pr(t,e,n){for(var r=-1,o=e.length,i={};++r-1;)a!==t&&Jt.call(a,c,1),Jt.call(t,c,1);return t}function Rr(t,e){for(var n=t?e.length:0,r=n-1;n--;){var o=e[n];if(n==r||o!==i){var i=o;ai(o)?Jt.call(t,o,1):Xr(t,o)}}return t}function Br(t,e){return t+Xe(fn()*(e-t+1))}function Lr(t,e){var n="";if(!t||e<1||e>9007199254740991)return n;do{e%2&&(n+=t),(e=Xe(e/2))&&(t+=t)}while(e);return n}function Tr(t,e){return bi(hi(t,e,Va),t+"")}function Mr(t){return Mn(Sa(t))}function Wr(t,e){var n=Sa(t);return Fi(n,Jn(e,0,n.length))}function Ur(t,e,n,r){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),(n=n>i?i:n)<0&&(n+=i),i=e>n?0:n-e>>>0,e>>>=0;for(var u=r(i);++o>>1,u=t[i];null!==u&&!Ku(u)&&(n?u<=e:u=200){var l=e?null:To(t);if(l)return $e(l);u=!1,o=Ne,c=new Bn}else c=e?[]:a;t:for(;++r=r?t:Gr(t,e,n)}var fo=Je||function(t){return Ht.clearTimeout(t)};function so(t,e){if(e)return t.slice();var n=t.length,r=zt?zt(n):new t.constructor(n);return t.copy(r),r}function po(t){var e=new t.constructor(t.byteLength);return new Bt(e).set(new Bt(t)),e}function vo(t,e){var n=e?po(t.buffer):t.buffer;return new t.constructor(n,t.byteOffset,t.length)}function ho(t,e){if(t!==e){var n=void 0!==t,r=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||r&&u&&c||!n&&c||!o)return 1;if(!r&&!i&&!l&&t1?n[o-1]:void 0,u=o>2?n[2]:void 0;for(i=t.length>3&&"function"==typeof i?(o--,i):void 0,u&&ci(n[0],n[1],u)&&(i=o<3?void 0:i,o=1),e=ht(e);++r-1?o[i?e[u]:u]:void 0}}function Oo(t){return Go((function(e){var n=e.length,r=n,o=Cn.prototype.thru;for(t&&e.reverse();r--;){var u=e[r];if("function"!=typeof u)throw new mt(i);if(o&&!a&&"wrapper"==Jo(u))var a=new Cn([],!0)}for(r=a?r:n;++r1&&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&n?new Bn:void 0;for(i.set(t,e),i.set(e,t);++f-1&&t%1==0&&t1?"& ":"")+e[r],e=e.join(n>2?", ":" "),t.replace(K,"{\n/* [wrapped with "+e+"] */\n")}(r,function(t,e){return ae(a,(function(n){var r="_."+n[0];e&n[1]&&!se(t,r)&&t.push(r)})),t.sort()}(function(t){var e=t.match(Y);return e?e[1].split(X):[]}(r),n)))}function wi(t){var e=0,n=0;return function(){var r=cn(),o=16-(r-n);if(n=r,o>0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}function Fi(t,e){var n=-1,r=t.length,o=r-1;for(e=void 0===e?r:e;++n1?t[e-1]:void 0;return n="function"==typeof n?(t.pop(),n):void 0,Qi(t,n)}));function eu(t){var e=On(t);return e.__chain__=!0,e}function nu(t,e){return e(t)}var ru=Go((function(t){var e=t.length,n=e?t[0]:0,r=this.__wrapped__,o=function(e){return Qn(e,t)};return!(e>1||this.__actions__.length)&&r instanceof Nn&&ai(n)?((r=r.slice(n,+n+(e?1:0))).__actions__.push({func:nu,args:[o],thisArg:void 0}),new Cn(r,this.__chain__).thru((function(t){return e&&!t.length&&t.push(void 0),t}))):this.thru(o)}));var ou=_o((function(t,e,n){Ft.call(t,n)?++t[n]:Hn(t,n,1)}));var iu=xo(Ni),uu=xo(Pi);function au(t,e){return(Pu(t)?ae:tr)(t,Ko(e,3))}function cu(t,e){return(Pu(t)?ce:er)(t,Ko(e,3))}var lu=_o((function(t,e,n){Ft.call(t,n)?t[n].push(e):Hn(t,n,[e])}));var fu=Tr((function(t,e,n){var o=-1,i="function"==typeof e,u=Ru(t)?r(t.length):[];return tr(t,(function(t){u[++o]=i?ie(e,t,n):mr(t,e,n)})),u})),su=_o((function(t,e,n){Hn(t,n,e)}));function pu(t,e){return(Pu(t)?ve:xr)(t,Ko(e,3))}var vu=_o((function(t,e,n){t[n?0:1].push(e)}),(function(){return[[],[]]}));var du=Tr((function(t,e){if(null==t)return[];var n=e.length;return n>1&&ci(t,e[0],e[1])?e=[]:n>2&&ci(e[0],e[1],e[2])&&(e=[e[0]]),Nr(t,ir(e,1),[])})),hu=Ze||function(){return Ht.Date.now()};function yu(t,e,n){return e=n?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 n;if("function"!=typeof e)throw new mt(i);return t=ra(t),function(){return--t>0&&(n=e.apply(this,arguments)),t<=1&&(e=void 0),n}}var mu=Tr((function(t,e,n){var r=1;if(n.length){var o=ze(n,Zo(mu));r|=32}return Wo(t,r,e,n,o)})),Du=Tr((function(t,e,n){var r=3;if(n.length){var o=ze(n,Zo(Du));r|=32}return Wo(e,r,t,n,o)}));function _u(t,e,n){var r,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 n=r,i=o;return r=o=void 0,f=e,a=t.apply(i,n)}function h(t){return f=t,c=_i(g,e),s?d(t):a}function y(t){var n=t-l;return void 0===l||n>=e||n<0||p&&t-f>=u}function g(){var t=hu();if(y(t))return m(t);c=_i(g,function(t){var n=e-(t-l);return p?an(n,u-(t-f)):n}(t))}function m(t){return c=void 0,v&&r?d(t):(r=o=void 0,a)}function D(){var t=hu(),n=y(t);if(r=arguments,o=this,l=t,n){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(n)&&(s=!!n.leading,u=(p="maxWait"in n)?un(ia(n.maxWait)||0,e):u,v="trailing"in n?!!n.trailing:v),D.cancel=function(){void 0!==c&&fo(c),f=0,r=l=o=c=void 0},D.flush=function(){return void 0===c?a:m(hu())},D}var bu=Tr((function(t,e){return Yn(t,1,e)})),Eu=Tr((function(t,e,n){return Yn(t,ia(e)||0,n)}));function wu(t,e){if("function"!=typeof t||null!=e&&"function"!=typeof e)throw new mt(i);var n=function(){var r=arguments,o=e?e.apply(this,r):r[0],i=n.cache;if(i.has(o))return i.get(o);var u=t.apply(this,r);return n.cache=i.set(o,u)||i,u};return n.cache=new(wu.Cache||Rn),n}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=Rn;var Au=co((function(t,e){var n=(e=1==e.length&&Pu(e[0])?ve(e[0],ke(Ko())):ve(ir(e,1),ke(Ko()))).length;return Tr((function(r){for(var o=-1,i=an(r.length,n);++o=e})),Nu=Dr(function(){return arguments}())?Dr:function(t){return qu(t)&&Ft.call(t,"callee")&&!Qt.call(t,"callee")},Pu=r.isArray,Iu=Xt?ke(Xt):function(t){return qu(t)&&vr(t)==w};function Ru(t){return null!=t&&zu(t.length)&&!Wu(t)}function Bu(t){return qu(t)&&Ru(t)}var Lu=en||ic,Tu=te?ke(te):function(t){return qu(t)&&vr(t)==s};function Mu(t){if(!qu(t))return!1;var e=vr(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=vr(t);return e==v||e==d||"[object AsyncFunction]"==e||"[object Proxy]"==e}function Uu(t){return"number"==typeof t&&t==ra(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)&&ri(t)==h};function Vu(t){return"number"==typeof t||qu(t)&&vr(t)==y}function Hu(t){if(!qu(t)||vr(t)!=g)return!1;var e=Gt(t);if(null===e)return!0;var n=Ft.call(e,"constructor")&&e.constructor;return"function"==typeof n&&n instanceof n&&wt.call(n)==Ot}var Qu=ne?ke(ne):function(t){return qu(t)&&vr(t)==m};var Ju=re?ke(re):function(t){return qu(t)&&ri(t)==D};function Zu(t){return"string"==typeof t||!Pu(t)&&qu(t)&&vr(t)==_}function Ku(t){return"symbol"==typeof t||qu(t)&&vr(t)==b}var Yu=oe?ke(oe):function(t){return qu(t)&&zu(t.length)&&!!Wt[vr(t)]};var Xu=Ro(jr),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,n=[];!(e=t.next()).done;)n.push(e.value);return n}(t[Yt]());var e=ri(t);return(e==h?We:e==D?$e:Sa)(t)}function na(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 ra(t){var e=na(t),n=e%1;return e==e?n?e-n:e:0}function oa(t){return t?Jn(ra(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 n=it.test(t);return n||at.test(t)?qt(t.slice(2),n?2:8):ot.test(t)?NaN:+t}function ua(t){return Do(t,ba(t))}function aa(t){return null==t?"":Kr(t)}var ca=bo((function(t,e){if(pi(e)||Ru(e))Do(e,_a(e),t);else for(var n in e)Ft.call(e,n)&&$n(t,n,e[n])})),la=bo((function(t,e){Do(e,ba(e),t)})),fa=bo((function(t,e,n,r){Do(e,ba(e),t,r)})),sa=bo((function(t,e,n,r){Do(e,_a(e),t,r)})),pa=Go(Qn);var va=Tr((function(t,e){t=ht(t);var n=-1,r=e.length,o=r>2?e[2]:void 0;for(o&&ci(e[0],e[1],o)&&(r=1);++n1),e})),Do(t,Ho(t),n),r&&(n=Zn(n,7,$o));for(var o=e.length;o--;)Xr(n,e[o]);return n}));var Aa=Go((function(t,e){return null==t?{}:function(t,e){return Pr(t,e,(function(e,n){return ya(t,n)}))}(t,e)}));function ja(t,e){if(null==t)return{};var n=ve(Ho(t),(function(t){return[t]}));return e=Ko(e),Pr(t,n,(function(t,n){return e(t,n[0])}))}var xa=Mo(_a),Oa=Mo(ba);function Sa(t){return null==t?[]:Ce(t,_a(t))}var ka=Ao((function(t,e,n){return e=e.toLowerCase(),t+(n?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=Ao((function(t,e,n){return t+(n?"-":"")+e.toLowerCase()})),Ia=Ao((function(t,e,n){return t+(n?" ":"")+e.toLowerCase()})),Ra=Fo("toLowerCase");var Ba=Ao((function(t,e,n){return t+(n?"_":"")+e.toLowerCase()}));var La=Ao((function(t,e,n){return t+(n?" ":"")+Ma(e)}));var Ta=Ao((function(t,e,n){return t+(n?" ":"")+e.toUpperCase()})),Ma=Fo("toUpperCase");function Wa(t,e,n){return t=aa(t),void 0===(e=n?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=Tr((function(t,e){try{return ie(t,void 0,e)}catch(n){return Mu(n)?n:new pt(n)}})),za=Go((function(t,e){return ae(e,(function(e){e=ji(e),Hn(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 wr("function"==typeof t?t:Zn(t,1))}var Qa=Tr((function(t,e){return function(n){return mr(n,t,e)}})),Ja=Tr((function(t,e){return function(n){return mr(t,n,e)}}));function Za(t,e,n){var r=_a(e),o=fr(e,r);null!=n||$u(e)&&(o.length||!r.length)||(n=e,e=t,t=this,o=fr(e,_a(e)));var i=!($u(n)&&"chain"in n&&!n.chain),u=Wu(t);return ae(o,(function(n){var r=e[n];t[n]=r,u&&(t.prototype[n]=function(){var e=this.__chain__;if(i||e){var n=t(this.__wrapped__),o=n.__actions__=mo(this.__actions__);return o.push({func:r,args:arguments,thisArg:t}),n.__chain__=e,n}return r.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)?Ae(ji(t)):function(t){return function(e){return sr(e,t)}}(t)}var nc=Io(),rc=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 On.after=function(t,e){if("function"!=typeof e)throw new mt(i);return t=ra(t),function(){if(--t<1)return e.apply(this,arguments)}},On.ary=yu,On.assign=ca,On.assignIn=la,On.assignInWith=fa,On.assignWith=sa,On.at=pa,On.before=gu,On.bind=mu,On.bindAll=za,On.bindKey=Du,On.castArray=function(){if(!arguments.length)return[];var t=arguments[0];return Pu(t)?t:[t]},On.chain=eu,On.chunk=function(t,e,n){e=(n?ci(t,e,n):void 0===e)?1:un(ra(e),0);var o=null==t?0:t.length;if(!o||e<1)return[];for(var i=0,u=0,a=r(Ye(o/e));io?0:o+n),(r=void 0===r||r>o?o:ra(r))<0&&(r+=o),r=n>r?0:oa(r);n>>0)?(t=aa(t))&&("string"==typeof e||null!=e&&!Qu(e))&&!(e=Kr(e))&&Me(t)?lo(Ve(t),0,n):t.split(e,n):[]},On.spread=function(t,e){if("function"!=typeof t)throw new mt(i);return e=null==e?0:un(ra(e),0),Tr((function(n){var r=n[e],o=lo(n,0,e);return r&&de(o,r),ie(t,this,o)}))},On.tail=function(t){var e=null==t?0:t.length;return e?Gr(t,1,e):[]},On.take=function(t,e,n){return t&&t.length?Gr(t,0,(e=n||void 0===e?1:ra(e))<0?0:e):[]},On.takeRight=function(t,e,n){var r=null==t?0:t.length;return r?Gr(t,(e=r-(e=n||void 0===e?1:ra(e)))<0?0:e,r):[]},On.takeRightWhile=function(t,e){return t&&t.length?eo(t,Ko(e,3),!1,!0):[]},On.takeWhile=function(t,e){return t&&t.length?eo(t,Ko(e,3)):[]},On.tap=function(t,e){return e(t),t},On.throttle=function(t,e,n){var r=!0,o=!0;if("function"!=typeof t)throw new mt(i);return $u(n)&&(r="leading"in n?!!n.leading:r,o="trailing"in n?!!n.trailing:o),_u(t,e,{leading:r,maxWait:e,trailing:o})},On.thru=nu,On.toArray=ea,On.toPairs=xa,On.toPairsIn=Oa,On.toPath=function(t){return Pu(t)?ve(t,ji):Ku(t)?[t]:mo(Ai(aa(t)))},On.toPlainObject=ua,On.transform=function(t,e,n){var r=Pu(t),o=r||Lu(t)||Yu(t);if(e=Ko(e,4),null==n){var i=t&&t.constructor;n=o?r?new i:[]:$u(t)&&Wu(i)?Sn(Gt(t)):{}}return(o?ae:cr)(t,(function(t,r,o){return e(n,t,r,o)})),n},On.unary=function(t){return yu(t,1)},On.union=qi,On.unionBy=Gi,On.unionWith=Vi,On.uniq=function(t){return t&&t.length?Yr(t):[]},On.uniqBy=function(t,e){return t&&t.length?Yr(t,Ko(e,2)):[]},On.uniqWith=function(t,e){return e="function"==typeof e?e:void 0,t&&t.length?Yr(t,void 0,e):[]},On.unset=function(t,e){return null==t||Xr(t,e)},On.unzip=Hi,On.unzipWith=Qi,On.update=function(t,e,n){return null==t?t:to(t,e,uo(n))},On.updateWith=function(t,e,n,r){return r="function"==typeof r?r:void 0,null==t?t:to(t,e,uo(n),r)},On.values=Sa,On.valuesIn=function(t){return null==t?[]:Ce(t,ba(t))},On.without=Ji,On.words=Wa,On.wrap=function(t,e){return ju(uo(e),t)},On.xor=Zi,On.xorBy=Ki,On.xorWith=Yi,On.zip=Xi,On.zipObject=function(t,e){return oo(t||[],e||[],$n)},On.zipObjectDeep=function(t,e){return oo(t||[],e||[],Ur)},On.zipWith=tu,On.entries=xa,On.entriesIn=Oa,On.extend=la,On.extendWith=fa,Za(On,On),On.add=uc,On.attempt=Ua,On.camelCase=ka,On.capitalize=Ca,On.ceil=ac,On.clamp=function(t,e,n){return void 0===n&&(n=e,e=void 0),void 0!==n&&(n=(n=ia(n))==n?n:0),void 0!==e&&(e=(e=ia(e))==e?e:0),Jn(ia(t),e,n)},On.clone=function(t){return Zn(t,4)},On.cloneDeep=function(t){return Zn(t,5)},On.cloneDeepWith=function(t,e){return Zn(t,5,e="function"==typeof e?e:void 0)},On.cloneWith=function(t,e){return Zn(t,4,e="function"==typeof e?e:void 0)},On.conformsTo=function(t,e){return null==e||Kn(t,e,_a(e))},On.deburr=Na,On.defaultTo=function(t,e){return null==t||t!=t?e:t},On.divide=cc,On.endsWith=function(t,e,n){t=aa(t),e=Kr(e);var r=t.length,o=n=void 0===n?r:Jn(ra(n),0,r);return(n-=e.length)>=0&&t.slice(n,o)==e},On.eq=Su,On.escape=function(t){return(t=aa(t))&&M.test(t)?t.replace(L,Le):t},On.escapeRegExp=function(t){return(t=aa(t))&&H.test(t)?t.replace(V,"\\$&"):t},On.every=function(t,e,n){var r=Pu(t)?le:nr;return n&&ci(t,e,n)&&(e=void 0),r(t,Ko(e,3))},On.find=iu,On.findIndex=Ni,On.findKey=function(t,e){return De(t,Ko(e,3),cr)},On.findLast=uu,On.findLastIndex=Pi,On.findLastKey=function(t,e){return De(t,Ko(e,3),lr)},On.floor=lc,On.forEach=au,On.forEachRight=cu,On.forIn=function(t,e){return null==t?t:ur(t,Ko(e,3),ba)},On.forInRight=function(t,e){return null==t?t:ar(t,Ko(e,3),ba)},On.forOwn=function(t,e){return t&&cr(t,Ko(e,3))},On.forOwnRight=function(t,e){return t&&lr(t,Ko(e,3))},On.get=ha,On.gt=ku,On.gte=Cu,On.has=function(t,e){return null!=t&&oi(t,e,hr)},On.hasIn=ya,On.head=Ri,On.identity=Va,On.includes=function(t,e,n,r){t=Ru(t)?t:Sa(t),n=n&&!r?ra(n):0;var o=t.length;return n<0&&(n=un(o+n,0)),Zu(t)?n<=o&&t.indexOf(e,n)>-1:!!o&&be(t,e,n)>-1},On.indexOf=function(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var o=null==n?0:ra(n);return o<0&&(o=un(r+o,0)),be(t,e,o)},On.inRange=function(t,e,n){return e=na(e),void 0===n?(n=e,e=0):n=na(n),function(t,e,n){return t>=an(e,n)&&t=-9007199254740991&&t<=9007199254740991},On.isSet=Ju,On.isString=Zu,On.isSymbol=Ku,On.isTypedArray=Yu,On.isUndefined=function(t){return void 0===t},On.isWeakMap=function(t){return qu(t)&&ri(t)==E},On.isWeakSet=function(t){return qu(t)&&"[object WeakSet]"==vr(t)},On.join=function(t,e){return null==t?"":rn.call(t,e)},On.kebabCase=Pa,On.last=Mi,On.lastIndexOf=function(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var o=r;return void 0!==n&&(o=(o=ra(n))<0?un(r+o,0):an(o,r-1)),e==e?function(t,e,n){for(var r=n+1;r--;)if(t[r]===e)return r;return r}(t,e,o):_e(t,we,o,!0)},On.lowerCase=Ia,On.lowerFirst=Ra,On.lt=Xu,On.lte=ta,On.max=function(t){return t&&t.length?rr(t,Va,dr):void 0},On.maxBy=function(t,e){return t&&t.length?rr(t,Ko(e,2),dr):void 0},On.mean=function(t){return Fe(t,Va)},On.meanBy=function(t,e){return Fe(t,Ko(e,2))},On.min=function(t){return t&&t.length?rr(t,Va,jr):void 0},On.minBy=function(t,e){return t&&t.length?rr(t,Ko(e,2),jr):void 0},On.stubArray=oc,On.stubFalse=ic,On.stubObject=function(){return{}},On.stubString=function(){return""},On.stubTrue=function(){return!0},On.multiply=sc,On.nth=function(t,e){return t&&t.length?Cr(t,ra(e)):void 0},On.noConflict=function(){return Ht._===this&&(Ht._=St),this},On.noop=Ka,On.now=hu,On.pad=function(t,e,n){t=aa(t);var r=(e=ra(e))?Ge(t):0;if(!e||r>=e)return t;var o=(e-r)/2;return Po(Xe(o),n)+t+Po(Ye(o),n)},On.padEnd=function(t,e,n){t=aa(t);var r=(e=ra(e))?Ge(t):0;return e&&re){var r=t;t=e,e=r}if(n||t%1||e%1){var o=fn();return an(t+o*(e-t+$t("1e-"+((o+"").length-1))),e)}return Br(t,e)},On.reduce=function(t,e,n){var r=Pu(t)?he:xe,o=arguments.length<3;return r(t,Ko(e,4),n,o,tr)},On.reduceRight=function(t,e,n){var r=Pu(t)?ye:xe,o=arguments.length<3;return r(t,Ko(e,4),n,o,er)},On.repeat=function(t,e,n){return e=(n?ci(t,e,n):void 0===e)?1:ra(e),Lr(aa(t),e)},On.replace=function(){var t=arguments,e=aa(t[0]);return t.length<3?e:e.replace(t[1],t[2])},On.result=function(t,e,n){var r=-1,o=(e=ao(e,t)).length;for(o||(o=1,t=void 0);++r9007199254740991)return[];var n=4294967295,r=an(t,4294967295);t-=4294967295;for(var o=Se(r,e=Ko(e));++n=i)return t;var a=n-Ge(r);if(a<1)return r;var c=u?lo(u,0,a).join(""):t.slice(0,a);if(void 0===o)return c+r;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(rt.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(Kr(o),a)!=a){var p=c.lastIndexOf(o);p>-1&&(c=c.slice(0,p))}return c+r},On.unescape=function(t){return(t=aa(t))&&T.test(t)?t.replace(B,He):t},On.uniqueId=function(t){var e=++At;return aa(t)+e},On.upperCase=Ta,On.upperFirst=Ma,On.each=au,On.eachRight=cu,On.first=Ri,Za(On,(fc={},cr(On,(function(t,e){Ft.call(On.prototype,e)||(fc[e]=t)})),fc),{chain:!1}),On.VERSION="4.17.15",ae(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(t){On[t].placeholder=On})),ae(["drop","take"],(function(t,e){Nn.prototype[t]=function(n){n=void 0===n?1:un(ra(n),0);var r=this.__filtered__&&!e?new Nn(this):this.clone();return r.__filtered__?r.__takeCount__=an(n,r.__takeCount__):r.__views__.push({size:an(n,4294967295),type:t+(r.__dir__<0?"Right":"")}),r},Nn.prototype[t+"Right"]=function(e){return this.reverse()[t](e).reverse()}})),ae(["filter","map","takeWhile"],(function(t,e){var n=e+1,r=1==n||3==n;Nn.prototype[t]=function(t){var e=this.clone();return e.__iteratees__.push({iteratee:Ko(t,3),type:n}),e.__filtered__=e.__filtered__||r,e}})),ae(["head","last"],(function(t,e){var n="take"+(e?"Right":"");Nn.prototype[t]=function(){return this[n](1).value()[0]}})),ae(["initial","tail"],(function(t,e){var n="drop"+(e?"":"Right");Nn.prototype[t]=function(){return this.__filtered__?new Nn(this):this[n](1)}})),Nn.prototype.compact=function(){return this.filter(Va)},Nn.prototype.find=function(t){return this.filter(t).head()},Nn.prototype.findLast=function(t){return this.reverse().find(t)},Nn.prototype.invokeMap=Tr((function(t,e){return"function"==typeof t?new Nn(this):this.map((function(n){return mr(n,t,e)}))})),Nn.prototype.reject=function(t){return this.filter(Fu(Ko(t)))},Nn.prototype.slice=function(t,e){t=ra(t);var n=this;return n.__filtered__&&(t>0||e<0)?new Nn(n):(t<0?n=n.takeRight(-t):t&&(n=n.drop(t)),void 0!==e&&(n=(e=ra(e))<0?n.dropRight(-e):n.take(e-t)),n)},Nn.prototype.takeRightWhile=function(t){return this.reverse().takeWhile(t).reverse()},Nn.prototype.toArray=function(){return this.take(4294967295)},cr(Nn.prototype,(function(t,e){var n=/^(?:filter|find|map|reject)|While$/.test(e),r=/^(?:head|last)$/.test(e),o=On[r?"take"+("last"==e?"Right":""):e],i=r||/^find/.test(e);o&&(On.prototype[e]=function(){var e=this.__wrapped__,u=r?[1]:arguments,a=e instanceof Nn,c=u[0],l=a||Pu(e),f=function(t){var e=o.apply(On,de([t],u));return r&&s?e[0]:e};l&&n&&"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 Nn(this);var h=t.apply(e,u);return h.__actions__.push({func:nu,args:[f],thisArg:void 0}),new Cn(h,s)}return v&&d?t.apply(this,u):(h=this.thru(f),v?r?h.value()[0]:h.value():h)})})),ae(["pop","push","shift","sort","splice","unshift"],(function(t){var e=Dt[t],n=/^(?:push|sort|unshift)$/.test(t)?"tap":"thru",r=/^(?:pop|shift)$/.test(t);On.prototype[t]=function(){var t=arguments;if(r&&!this.__chain__){var o=this.value();return e.apply(Pu(o)?o:[],t)}return this[n]((function(n){return e.apply(Pu(n)?n:[],t)}))}})),cr(Nn.prototype,(function(t,e){var n=On[e];if(n){var r=n.name+"";Ft.call(Dn,r)||(Dn[r]=[]),Dn[r].push({name:e,func:n})}})),Dn[So(void 0,2).name]=[{name:"wrapper",func:void 0}],Nn.prototype.clone=function(){var t=new Nn(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},Nn.prototype.reverse=function(){if(this.__filtered__){var t=new Nn(this);t.__dir__=-1,t.__filtered__=!0}else(t=this.clone()).__dir__*=-1;return t},Nn.prototype.value=function(){var t=this.__wrapped__.value(),e=this.__dir__,n=Pu(t),r=e<0,o=n?t.length:0,i=function(t,e,n){var r=-1,o=n.length;for(;++r=this.__values__.length;return{done:t,value:t?void 0:this.__values__[this.__index__++]}},On.prototype.plant=function(t){for(var e,n=this;n instanceof kn;){var r=Oi(n);r.__index__=0,r.__values__=void 0,e?o.__wrapped__=r:e=r;var o=r;n=n.__wrapped__}return o.__wrapped__=t,e},On.prototype.reverse=function(){var t=this.__wrapped__;if(t instanceof Nn){var e=t;return this.__actions__.length&&(e=new Nn(this)),(e=e.reverse()).__actions__.push({func:nu,args:[$i],thisArg:void 0}),new Cn(e,this.__chain__)}return this.thru($i)},On.prototype.toJSON=On.prototype.valueOf=On.prototype.value=function(){return no(this.__wrapped__,this.__actions__)},On.prototype.first=On.prototype.head,Yt&&(On.prototype[Yt]=function(){return this}),On}();Ht._=Qe,void 0===(o=function(){return Qe}.call(e,n,e,r))||(r.exports=o)}).call(this)}).call(this,n(76),n(480)(t))},478:function(t,e,n){"use strict";var r=n(0),o=Object(r.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});e.a=o},479:function(t,e,n){"use strict";n.d(e,"a",(function(){return i}));n(77),n(497),n(462),n(78);var r=n(499),o=n.n(r);function i(t,e){var n=new o.a;return t.map((function(t){var r=t;return"string"==typeof t&&(r={label:t,permalink:"/blog/tags/"+n.slug(t)}),function(t,e){var n=t.label.split(": ",2),r=n[0],o=n[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"}}(r)}return{category:r,count:t.count,label:t.label,permalink:t.permalink,style:i,value:o}}(r,e)}))}},480: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}},489:function(t,e,n){var r=n(30),o=n(54),i=n(27),u=n(26),a=n(490);t.exports=function(t,e){var n=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=r(a,d,3),_=u(m.length),b=0,E=n?v(e,_):c?v(e,0):void 0;_>b;b++)if((p||b in m)&&(y=D(h=m[b],b,g),t))if(n)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}}},490:function(t,e,n){var r=n(491);t.exports=function(t,e){return new(r(t))(e)}},491:function(t,e,n){var r=n(13),o=n(492),i=n(2)("species");t.exports=function(t){var e;return o(t)&&("function"!=typeof(e=t.constructor)||e!==Array&&!o(e.prototype)||(e=void 0),r(e)&&null===(e=e[i])&&(e=void 0)),void 0===e?Array:e}},492:function(t,e,n){var r=n(23);t.exports=Array.isArray||function(t){return"Array"==r(t)}},493:function(t,e,n){"use strict";var r=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=n(531)(),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%":r,"%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=n(494),g=n(534),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,A=function(t){var e=b(t,0,1),n=b(t,-1);if("%"===e&&"%"!==n)throw new r("invalid intrinsic syntax, expected closing `%`");if("%"===n&&"%"!==e)throw new r("invalid intrinsic syntax, expected opening `%`");var o=[];return _(t,w,(function(t,e,n,r){o[o.length]=n?_(r,F,"$1"):e||t})),o},j=function(t,e){var n,o=t;if(g(h,o)&&(o="%"+(n=h[o])[0]+"%"),g(d,o)){var a=d[o];if(a===p&&(a=function t(e){var n;if("%AsyncFunction%"===e)n=u("async function () {}");else if("%GeneratorFunction%"===e)n=u("function* () {}");else if("%AsyncGeneratorFunction%"===e)n=u("async function* () {}");else if("%AsyncGenerator%"===e){var r=t("%AsyncGeneratorFunction%");r&&(n=r.prototype)}else if("%AsyncIteratorPrototype%"===e){var o=t("%AsyncGenerator%");o&&(n=s(o.prototype))}return d[e]=n,n}(o)),void 0===a&&!e)throw new i("intrinsic "+t+" exists, but is not available. Please file an issue!");return{alias:n,name:o,value:a}}throw new r("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 r("`%` may not be present anywhere but at the beginning and end of the intrinsic name");var n=A(t),o=n.length>0?n[0]:"",u=j("%"+o+"%",e),c=u.name,l=u.value,f=!1,s=u.alias;s&&(o=s[0],D(n,m([0,1],s)));for(var p=1,v=!0;p=n.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}},494:function(t,e,n){"use strict";var r=n(533);t.exports=Function.prototype.bind||r},495:function(t,e,n){"use strict";var r=String.prototype.replace,o=/%20/g,i="RFC1738",u="RFC3986";t.exports={default:u,formatters:{RFC1738:function(t){return r.call(t,o,"+")},RFC3986:function(t){return String(t)}},RFC1738:i,RFC3986:u}},498:function(t,e,n){"use strict";var r=n(0),o=n.n(r),i=n(454),u=n(447),a=n.n(u);e.a=function(t){var e=t.count,n=t.label,r=t.permalink,u=t.style,c=t.value,l=t.valueOnly;return o.a.createElement(i.a,{to:r+"/",className:a()("badge","badge--rounded","badge--"+u)},l?c:n,e&&o.a.createElement(o.a.Fragment,null," (",e,")"))}},499:function(t,e,n){var r=n(500);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(r(),"").replace(i,"-"))}a.prototype.slug=function(t,e){for(var n=c(t,!0===e),r=n;o.call(this.occurrences,n);)this.occurrences[r]++,n=r+"-"+this.occurrences[r];return this.occurrences[n]=0,n},a.prototype.reset=function(){this.occurrences=Object.create(null)},a.slug=c},500: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}},502:function(t,e,n){"use strict";var r=n(495),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 n=e&&e.plainObjects?Object.create(null):{},r=0;r1;){var e=t.pop(),n=e.obj[e.prop];if(i(n)){for(var r=[],o=0;o=48&&f<=57||f>=65&&f<=90||f>=97&&f<=122||i===r.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 n=[],r=0;r0?A.join(",")||null:void 0}];else if(c(v))I=v;else{var B=Object.keys(A);I=y?B.sort(y):B}for(var L=u&&c(A)&&1===A.length?n+"[]":n,T=0;T0?b+_:""}},530:function(t,e,n){"use strict";var r=n(493),o=n(535),i=n(537),u=r("%TypeError%"),a=r("%WeakMap%",!0),c=r("%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 n,r=t;null!==(n=r.next);r=n)if(n.key===e)return r.next=n.next,n.next=t.next,t.next=n,n};t.exports=function(){var t,e,n,r={assert:function(t){if(!r.has(t))throw new u("Side channel does not contain "+i(t))},get:function(r){if(a&&r&&("object"==typeof r||"function"==typeof r)){if(t)return l(t,r)}else if(c){if(e)return p(e,r)}else if(n)return function(t,e){var n=h(t,e);return n&&n.value}(n,r)},has:function(r){if(a&&r&&("object"==typeof r||"function"==typeof r)){if(t)return s(t,r)}else if(c){if(e)return d(e,r)}else if(n)return function(t,e){return!!h(t,e)}(n,r);return!1},set:function(r,o){a&&r&&("object"==typeof r||"function"==typeof r)?(t||(t=new a),f(t,r,o)):c?(e||(e=new c),v(e,r,o)):(n||(n={key:{},next:null}),function(t,e,n){var r=h(t,e);r?r.value=n:t.next={key:e,next:t.next,value:n}}(n,r,o))}};return r}},531:function(t,e,n){"use strict";var r="undefined"!=typeof Symbol&&Symbol,o=n(532);t.exports=function(){return"function"==typeof r&&("function"==typeof Symbol&&("symbol"==typeof r("foo")&&("symbol"==typeof Symbol("bar")&&o())))}},532:function(t,e,n){"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"),n=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(n))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 r=Object.getOwnPropertySymbols(t);if(1!==r.length||r[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}},533:function(t,e,n){"use strict";var r="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(r+e);for(var n,u=o.call(arguments,1),a=function(){if(this instanceof n){var r=e.apply(this,u.concat(o.call(arguments)));return Object(r)===r?r:this}return e.apply(t,u.concat(o.call(arguments)))},c=Math.max(0,e.length-u.length),l=[],f=0;f-1?o(n):n}},536:function(t,e,n){"use strict";var r=n(494),o=n(493),i=o("%Function.prototype.apply%"),u=o("%Function.prototype.call%"),a=o("%Reflect.apply%",!0)||r.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(r,u,arguments);if(c&&l){var n=c(e,"length");n.configurable&&l(e,"length",{value:1+f(0,t.length-(arguments.length-1))})}return e};var s=function(){return a(r,i,arguments)};l?l(t.exports,"apply",{value:s}):t.exports.apply=s},537:function(t,e,n){var r="function"==typeof Map&&Map.prototype,o=Object.getOwnPropertyDescriptor&&r?Object.getOwnPropertyDescriptor(Map.prototype,"size"):null,i=r&&o&&"function"==typeof o.get?o.get:null,u=r&&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,A=Array.prototype.slice,j=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 n=/[0-9](?=(?:[0-9]{3})+(?![0-9]))/g;if("number"==typeof t){var r=t<0?-j(-t):j(t);if(r!==t){var o=String(r),i=m.call(e,o.length+1);return D.call(o,n,"$&_")+"."+D.call(D.call(i,/([0-9]{3})/g,"$&_"),/_$/,"")}}return D.call(e,n,"$&_")}var R=n(538),B=R.custom,L=z(B)?B:null;function T(t,e,n){var r="double"===(n.quoteStyle||e)?'"':"'";return r+t+r}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,n,r,o){var a=n||{};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,n){if(e.length>n.maxStringLength){var r=e.length-n.maxStringLength,o="... "+r+" more character"+(r>1?"s":"");return t(m.call(e,0,n.maxStringLength),n)+o}return T(D.call(D.call(e,/(['\\])/g,"\\$1"),/[\x00-\x1f]/g,H),"single",n)}(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 j=void 0===a.depth?5:a.depth;if(void 0===r&&(r=0),r>=j&&j>0&&"object"==typeof e)return W(e)?"[Array]":"[Object]";var O=function(t,e){var n;if("\t"===t.indent)n="\t";else{if(!("number"==typeof t.indent&&t.indent>0))return null;n=F.call(Array(t.indent+1)," ")}return{base:n,prev:F.call(Array(e+1),n)}}(a,r);if(void 0===o)o=[];else if(V(o,e)>=0)return"[Circular]";function B(e,n,i){if(n&&(o=A.call(o)).push(n),i){var u={depth:a.depth};return q(a,"quoteStyle")&&(u.quoteStyle=a.quoteStyle),t(e,u,r+1,o)}return t(e,a,r+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)),nt=e.attributes||[],rt=0;rt"}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:j-r});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,n){ut.push(B(n,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(n){}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 n=0,r=t.length;n-1?t.split(","):t},l=function(t,e,n,r){if(t){var i=n.allowDots?t.replace(/\.([^.[]+)/g,"[$1]"):t,u=/(\[[^[\]]*])/g,a=n.depth>0&&/(\[[^[\]]*])/.exec(i),l=a?i.slice(0,a.index):i,f=[];if(l){if(!n.plainObjects&&o.call(Object.prototype,l)&&!n.allowPrototypes)return;f.push(l)}for(var s=0;n.depth>0&&null!==(a=u.exec(i))&&s=0;--i){var u,a=t[i];if("[]"===a&&n.parseArrays)u=[].concat(o);else{u=n.plainObjects?Object.create(null):{};var l="["===a.charAt(0)&&"]"===a.charAt(a.length-1)?a.slice(1,-1):a,f=parseInt(l,10);n.parseArrays||""!==l?!isNaN(f)&&a!==l&&String(f)===l&&f>=0&&n.parseArrays&&f<=n.arrayLimit?(u=[])[f]=o:"__proto__"!==l&&(u[l]=o):u={0:o}}o=u}return o}(f,e,n,r)}};t.exports=function(t,e){var n=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||r.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 n.plainObjects?Object.create(null):{};for(var f="string"==typeof t?function(t,e){var n,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(n=0;n-1&&(y=i(y)?[y]:y),o.call(l,h)?l[h]=r.combine(l[h],y):l[h]=y}return l}(t,n):t,s=n.plainObjects?Object.create(null):{},p=Object.keys(f),v=0;v1?arguments[1]:void 0)}}),n(74)("find")},467:function(t,e,n){"use strict";var r=n(8),o=n(512),i=n(55);n(56)("search",1,(function(t,e,n,u){return[function(n){var r=t(this),o=null==n?void 0:n[e];return void 0!==o?o.call(n,r):new RegExp(n)[e](String(r))},function(t){var e=u(n,t,this);if(e.done)return e.value;var a=r(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}]}))},473:function(t,e,n){"use strict";n(483);var r=n(0),o=n.n(r),i=n(484),u=n(472),a=n(1),c=(n(474),n(475),n(485),n(456)),l=n(486),f=n(468),s=n.n(f),p=n(487),v=n.n(p),d=n(462),h=n(449),y=n.n(h),g=n(135),m=n.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,n=Date.parse(e.date),r=new Date,o=Math.abs(r-n),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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),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=n(488),W=n(489),U=n(3);n(138);e.a=function(t){var e=Object(d.a)().siteConfig,n=void 0===e?{}:e,r=n.favicon,a=(n.tagline,n.title),c=n.themeConfig.image,l=n.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)(r),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}),r&&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)))}},476:function(t,e,n){"use strict";var r=n(9),o=n(0),i=n.n(o),u=n(449),a=n.n(u),c=n(462),l=(n(139),n(140)),f=n.n(l);e.a=function(t){return function(e){var n,o=e.id,u=Object(r.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",(n={},n[f.a.enhancedAnchor]=!d,n)),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)}}},477:function(t,e,n){(function(t,r){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]",A="[object Float32Array]",j="[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,nt=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,rt=/\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]",At="[A-Z\\xc0-\\xd6\\xd8-\\xde]",jt="(?:"+Dt+"|"+_t+")",xt="(?:"+At+"|"+_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([At+"?"+Dt+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?="+[ht,At,"$"].join("|")+")",xt+"+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?="+[ht,At+jt,"$"].join("|")+")",At+"?"+jt+"+(?:['\u2019](?:d|ll|m|re|s|t|ve))?",At+"+(?:['\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[A]=Wt[j]=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[A]=Ut[j]=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 r&&r&&!r.nodeType&&r,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,ne=Yt&&Yt.isRegExp,re=Yt&&Yt.isSet,oe=Yt&&Yt.isTypedArray;function ie(t,e,n){switch(n.length){case 0:return t.call(e);case 1:return t.call(e,n[0]);case 2:return t.call(e,n[0],n[1]);case 3:return t.call(e,n[0],n[1],n[2])}return t.apply(e,n)}function ue(t,e,n,r){for(var o=-1,i=null==t?0:t.length;++o-1}function pe(t,e,n){for(var r=-1,o=null==t?0:t.length;++r-1;);return n}function Ie(t,e){for(var n=t.length;n--&&be(e,t[n],0)>-1;);return n}function Re(t,e){for(var n=t.length,r=0;n--;)t[n]===e&&++r;return r}var Be=je({"\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=je({"&":"&","<":"<",">":">",'"':""","'":"'"});function Te(t){return"\\"+zt[t]}function Me(t){return Bt.test(t)}function We(t){var e=-1,n=Array(t.size);return t.forEach((function(t,r){n[++e]=[r,t]})),n}function Ue(t,e){return function(n){return t(e(n))}}function ze(t,e){for(var n=-1,r=t.length,o=0,i=[];++n",""":'"',"'":"'"});var Qe=function t(e){var n,r=(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=r.prototype,_t=vt.prototype,bt=ht.prototype,Et=e["__core-js_shared__"],wt=_t.toString,Ft=bt.hasOwnProperty,At=0,jt=(n=/[^.]+$/.exec(Et&&Et.keys&&Et.keys.IE_PROTO||""))?"Symbol(src)_1."+n:"",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,je=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,tn=ht.getOwnPropertySymbols,en=Ct?Ct.isBuffer:void 0,nn=e.isFinite,rn=Dt.join,on=Ue(ht.keys,ht),un=dt.max,an=dt.min,cn=o.now,ln=e.parseInt,fn=dt.random,sn=Dt.reverse,pn=ti(e,"DataView"),vn=ti(e,"Map"),dn=ti(e,"Promise"),hn=ti(e,"Set"),yn=ti(e,"WeakMap"),gn=ti(ht,"create"),mn=yn&&new yn,Dn={},_n=xi(pn),bn=xi(vn),En=xi(dn),wn=xi(hn),Fn=xi(yn),An=It?It.prototype:void 0,jn=An?An.valueOf:void 0,xn=An?An.toString:void 0;function On(t){if(qu(t)&&!Pu(t)&&!(t instanceof Nn)){if(t instanceof Cn)return t;if(Ft.call(t,"__wrapped__"))return Oi(t)}return new Cn(t)}var Sn=function(){function t(){}return function(e){if(!$u(e))return{};if(Vt)return Vt(e);t.prototype=e;var n=new t;return t.prototype=void 0,n}}();function kn(){}function Cn(t,e){this.__wrapped__=t,this.__actions__=[],this.__chain__=!!e,this.__index__=0,this.__values__=void 0}function Nn(t){this.__wrapped__=t,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Pn(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e=e?t:e)),t}function Zn(t,e,n,r,o,i){var u,a=1&e,l=2&e,p=4&e;if(n&&(u=o?n(t,r,o,i):n(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,n=new t.constructor(e);e&&"string"==typeof t[0]&&Ft.call(t,"index")&&(n.index=t.index,n.input=t.input);return n}(t),!a)return mo(t,u)}else{var P=ri(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,ni(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,Vn(u,t))}else{if(!Ut[P])return o?t:{};u=function(t,e,n){var r=t.constructor;switch(e){case w:return po(t);case f:case s:return new r(+t);case F:return function(t,e){var n=e?po(t.buffer):t.buffer;return new t.constructor(n,t.byteOffset,t.byteLength)}(t,n);case A:case j:case x:case O:case S:case k:case"[object Uint8ClampedArray]":case C:case N:return vo(t,n);case h:return new r;case y:case _:return new r(t);case m:return function(t){var e=new t.constructor(t.source,rt.exec(t));return e.lastIndex=t.lastIndex,e}(t);case D:return new r;case b:return o=t,jn?ht(jn.call(o)):{}}var o}(t,P,a)}}i||(i=new Ln);var R=i.get(t);if(R)return R;i.set(t,u),Ju(t)?t.forEach((function(r){u.add(Zn(r,e,n,r,t,i))})):Gu(t)&&t.forEach((function(r,o){u.set(o,Zn(r,e,n,o,t,i))}));var B=E?void 0:(p?l?Ho:Vo:l?ba:_a)(t);return ae(B||t,(function(r,o){B&&(r=t[o=r]),$n(u,o,Zn(r,e,n,o,t,i))})),u}function Kn(t,e,n){var r=n.length;if(null==t)return!r;for(t=ht(t);r--;){var o=n[r],i=e[o],u=t[o];if(void 0===u&&!(o in t)||!i(u))return!1}return!0}function Yn(t,e,n){if("function"!=typeof t)throw new mt(i);return _i((function(){t.apply(void 0,n)}),e)}function Xn(t,e,n,r){var o=-1,i=se,u=!0,a=t.length,c=[],l=e.length;if(!a)return c;n&&(e=ve(e,ke(n))),r?(i=pe,u=!1):e.length>=200&&(i=Ne,u=!1,e=new Bn(e));t:for(;++o-1},In.prototype.set=function(t,e){var n=this.__data__,r=qn(n,t);return r<0?(++this.size,n.push([t,e])):n[r][1]=e,this},Rn.prototype.clear=function(){this.size=0,this.__data__={hash:new Pn,map:new(vn||In),string:new Pn}},Rn.prototype.delete=function(t){var e=Yo(this,t).delete(t);return this.size-=e?1:0,e},Rn.prototype.get=function(t){return Yo(this,t).get(t)},Rn.prototype.has=function(t){return Yo(this,t).has(t)},Rn.prototype.set=function(t,e){var n=Yo(this,t),r=n.size;return n.set(t,e),this.size+=n.size==r?0:1,this},Bn.prototype.add=Bn.prototype.push=function(t){return this.__data__.set(t,"__lodash_hash_undefined__"),this},Bn.prototype.has=function(t){return this.__data__.has(t)},Ln.prototype.clear=function(){this.__data__=new In,this.size=0},Ln.prototype.delete=function(t){var e=this.__data__,n=e.delete(t);return this.size=e.size,n},Ln.prototype.get=function(t){return this.__data__.get(t)},Ln.prototype.has=function(t){return this.__data__.has(t)},Ln.prototype.set=function(t,e){var n=this.__data__;if(n instanceof In){var r=n.__data__;if(!vn||r.length<199)return r.push([t,e]),this.size=++n.size,this;n=this.__data__=new Rn(r)}return n.set(t,e),this.size=n.size,this};var tr=Eo(cr),er=Eo(lr,!0);function nr(t,e){var n=!0;return tr(t,(function(t,r,o){return n=!!e(t,r,o)})),n}function rr(t,e,n){for(var r=-1,o=t.length;++r0&&n(a)?e>1?ir(a,e-1,n,r,o):de(o,a):r||(o[o.length]=a)}return o}var ur=wo(),ar=wo(!0);function cr(t,e){return t&&ur(t,e,_a)}function lr(t,e){return t&&ar(t,e,_a)}function fr(t,e){return fe(e,(function(e){return Wu(t[e])}))}function sr(t,e){for(var n=0,r=(e=ao(e,t)).length;null!=t&&ne}function hr(t,e){return null!=t&&Ft.call(t,e)}function yr(t,e){return null!=t&&e in ht(t)}function gr(t,e,n){for(var o=n?pe:se,i=t[0].length,u=t.length,a=u,c=r(u),l=1/0,f=[];a--;){var s=t[a];a&&e&&(s=ve(s,ke(e))),l=an(s.length,l),c[a]=!n&&(e||i>=120&&s.length>=120)?new Bn(a&&s):void 0}s=t[0];var p=-1,v=c[0];t:for(;++p=a)return c;var l=n[r];return c*("desc"==l?-1:1)}}return t.index-e.index}(t,e,n)}))}function Pr(t,e,n){for(var r=-1,o=e.length,i={};++r-1;)a!==t&&Jt.call(a,c,1),Jt.call(t,c,1);return t}function Rr(t,e){for(var n=t?e.length:0,r=n-1;n--;){var o=e[n];if(n==r||o!==i){var i=o;ai(o)?Jt.call(t,o,1):Xr(t,o)}}return t}function Br(t,e){return t+Xe(fn()*(e-t+1))}function Lr(t,e){var n="";if(!t||e<1||e>9007199254740991)return n;do{e%2&&(n+=t),(e=Xe(e/2))&&(t+=t)}while(e);return n}function Tr(t,e){return bi(hi(t,e,Va),t+"")}function Mr(t){return Mn(Sa(t))}function Wr(t,e){var n=Sa(t);return Fi(n,Jn(e,0,n.length))}function Ur(t,e,n,r){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),(n=n>i?i:n)<0&&(n+=i),i=e>n?0:n-e>>>0,e>>>=0;for(var u=r(i);++o>>1,u=t[i];null!==u&&!Ku(u)&&(n?u<=e:u=200){var l=e?null:To(t);if(l)return $e(l);u=!1,o=Ne,c=new Bn}else c=e?[]:a;t:for(;++r=r?t:Gr(t,e,n)}var fo=Je||function(t){return Ht.clearTimeout(t)};function so(t,e){if(e)return t.slice();var n=t.length,r=zt?zt(n):new t.constructor(n);return t.copy(r),r}function po(t){var e=new t.constructor(t.byteLength);return new Bt(e).set(new Bt(t)),e}function vo(t,e){var n=e?po(t.buffer):t.buffer;return new t.constructor(n,t.byteOffset,t.length)}function ho(t,e){if(t!==e){var n=void 0!==t,r=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||r&&u&&c||!n&&c||!o)return 1;if(!r&&!i&&!l&&t1?n[o-1]:void 0,u=o>2?n[2]:void 0;for(i=t.length>3&&"function"==typeof i?(o--,i):void 0,u&&ci(n[0],n[1],u)&&(i=o<3?void 0:i,o=1),e=ht(e);++r-1?o[i?e[u]:u]:void 0}}function Oo(t){return Go((function(e){var n=e.length,r=n,o=Cn.prototype.thru;for(t&&e.reverse();r--;){var u=e[r];if("function"!=typeof u)throw new mt(i);if(o&&!a&&"wrapper"==Jo(u))var a=new Cn([],!0)}for(r=a?r:n;++r1&&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&n?new Bn:void 0;for(i.set(t,e),i.set(e,t);++f-1&&t%1==0&&t1?"& ":"")+e[r],e=e.join(n>2?", ":" "),t.replace(K,"{\n/* [wrapped with "+e+"] */\n")}(r,function(t,e){return ae(a,(function(n){var r="_."+n[0];e&n[1]&&!se(t,r)&&t.push(r)})),t.sort()}(function(t){var e=t.match(Y);return e?e[1].split(X):[]}(r),n)))}function wi(t){var e=0,n=0;return function(){var r=cn(),o=16-(r-n);if(n=r,o>0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}function Fi(t,e){var n=-1,r=t.length,o=r-1;for(e=void 0===e?r:e;++n1?t[e-1]:void 0;return n="function"==typeof n?(t.pop(),n):void 0,Qi(t,n)}));function eu(t){var e=On(t);return e.__chain__=!0,e}function nu(t,e){return e(t)}var ru=Go((function(t){var e=t.length,n=e?t[0]:0,r=this.__wrapped__,o=function(e){return Qn(e,t)};return!(e>1||this.__actions__.length)&&r instanceof Nn&&ai(n)?((r=r.slice(n,+n+(e?1:0))).__actions__.push({func:nu,args:[o],thisArg:void 0}),new Cn(r,this.__chain__).thru((function(t){return e&&!t.length&&t.push(void 0),t}))):this.thru(o)}));var ou=_o((function(t,e,n){Ft.call(t,n)?++t[n]:Hn(t,n,1)}));var iu=xo(Ni),uu=xo(Pi);function au(t,e){return(Pu(t)?ae:tr)(t,Ko(e,3))}function cu(t,e){return(Pu(t)?ce:er)(t,Ko(e,3))}var lu=_o((function(t,e,n){Ft.call(t,n)?t[n].push(e):Hn(t,n,[e])}));var fu=Tr((function(t,e,n){var o=-1,i="function"==typeof e,u=Ru(t)?r(t.length):[];return tr(t,(function(t){u[++o]=i?ie(e,t,n):mr(t,e,n)})),u})),su=_o((function(t,e,n){Hn(t,n,e)}));function pu(t,e){return(Pu(t)?ve:xr)(t,Ko(e,3))}var vu=_o((function(t,e,n){t[n?0:1].push(e)}),(function(){return[[],[]]}));var du=Tr((function(t,e){if(null==t)return[];var n=e.length;return n>1&&ci(t,e[0],e[1])?e=[]:n>2&&ci(e[0],e[1],e[2])&&(e=[e[0]]),Nr(t,ir(e,1),[])})),hu=Ze||function(){return Ht.Date.now()};function yu(t,e,n){return e=n?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 n;if("function"!=typeof e)throw new mt(i);return t=ra(t),function(){return--t>0&&(n=e.apply(this,arguments)),t<=1&&(e=void 0),n}}var mu=Tr((function(t,e,n){var r=1;if(n.length){var o=ze(n,Zo(mu));r|=32}return Wo(t,r,e,n,o)})),Du=Tr((function(t,e,n){var r=3;if(n.length){var o=ze(n,Zo(Du));r|=32}return Wo(e,r,t,n,o)}));function _u(t,e,n){var r,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 n=r,i=o;return r=o=void 0,f=e,a=t.apply(i,n)}function h(t){return f=t,c=_i(g,e),s?d(t):a}function y(t){var n=t-l;return void 0===l||n>=e||n<0||p&&t-f>=u}function g(){var t=hu();if(y(t))return m(t);c=_i(g,function(t){var n=e-(t-l);return p?an(n,u-(t-f)):n}(t))}function m(t){return c=void 0,v&&r?d(t):(r=o=void 0,a)}function D(){var t=hu(),n=y(t);if(r=arguments,o=this,l=t,n){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(n)&&(s=!!n.leading,u=(p="maxWait"in n)?un(ia(n.maxWait)||0,e):u,v="trailing"in n?!!n.trailing:v),D.cancel=function(){void 0!==c&&fo(c),f=0,r=l=o=c=void 0},D.flush=function(){return void 0===c?a:m(hu())},D}var bu=Tr((function(t,e){return Yn(t,1,e)})),Eu=Tr((function(t,e,n){return Yn(t,ia(e)||0,n)}));function wu(t,e){if("function"!=typeof t||null!=e&&"function"!=typeof e)throw new mt(i);var n=function(){var r=arguments,o=e?e.apply(this,r):r[0],i=n.cache;if(i.has(o))return i.get(o);var u=t.apply(this,r);return n.cache=i.set(o,u)||i,u};return n.cache=new(wu.Cache||Rn),n}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=Rn;var Au=co((function(t,e){var n=(e=1==e.length&&Pu(e[0])?ve(e[0],ke(Ko())):ve(ir(e,1),ke(Ko()))).length;return Tr((function(r){for(var o=-1,i=an(r.length,n);++o=e})),Nu=Dr(function(){return arguments}())?Dr:function(t){return qu(t)&&Ft.call(t,"callee")&&!Qt.call(t,"callee")},Pu=r.isArray,Iu=Xt?ke(Xt):function(t){return qu(t)&&vr(t)==w};function Ru(t){return null!=t&&zu(t.length)&&!Wu(t)}function Bu(t){return qu(t)&&Ru(t)}var Lu=en||ic,Tu=te?ke(te):function(t){return qu(t)&&vr(t)==s};function Mu(t){if(!qu(t))return!1;var e=vr(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=vr(t);return e==v||e==d||"[object AsyncFunction]"==e||"[object Proxy]"==e}function Uu(t){return"number"==typeof t&&t==ra(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)&&ri(t)==h};function Vu(t){return"number"==typeof t||qu(t)&&vr(t)==y}function Hu(t){if(!qu(t)||vr(t)!=g)return!1;var e=Gt(t);if(null===e)return!0;var n=Ft.call(e,"constructor")&&e.constructor;return"function"==typeof n&&n instanceof n&&wt.call(n)==Ot}var Qu=ne?ke(ne):function(t){return qu(t)&&vr(t)==m};var Ju=re?ke(re):function(t){return qu(t)&&ri(t)==D};function Zu(t){return"string"==typeof t||!Pu(t)&&qu(t)&&vr(t)==_}function Ku(t){return"symbol"==typeof t||qu(t)&&vr(t)==b}var Yu=oe?ke(oe):function(t){return qu(t)&&zu(t.length)&&!!Wt[vr(t)]};var Xu=Ro(jr),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,n=[];!(e=t.next()).done;)n.push(e.value);return n}(t[Yt]());var e=ri(t);return(e==h?We:e==D?$e:Sa)(t)}function na(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 ra(t){var e=na(t),n=e%1;return e==e?n?e-n:e:0}function oa(t){return t?Jn(ra(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 n=it.test(t);return n||at.test(t)?qt(t.slice(2),n?2:8):ot.test(t)?NaN:+t}function ua(t){return Do(t,ba(t))}function aa(t){return null==t?"":Kr(t)}var ca=bo((function(t,e){if(pi(e)||Ru(e))Do(e,_a(e),t);else for(var n in e)Ft.call(e,n)&&$n(t,n,e[n])})),la=bo((function(t,e){Do(e,ba(e),t)})),fa=bo((function(t,e,n,r){Do(e,ba(e),t,r)})),sa=bo((function(t,e,n,r){Do(e,_a(e),t,r)})),pa=Go(Qn);var va=Tr((function(t,e){t=ht(t);var n=-1,r=e.length,o=r>2?e[2]:void 0;for(o&&ci(e[0],e[1],o)&&(r=1);++n1),e})),Do(t,Ho(t),n),r&&(n=Zn(n,7,$o));for(var o=e.length;o--;)Xr(n,e[o]);return n}));var Aa=Go((function(t,e){return null==t?{}:function(t,e){return Pr(t,e,(function(e,n){return ya(t,n)}))}(t,e)}));function ja(t,e){if(null==t)return{};var n=ve(Ho(t),(function(t){return[t]}));return e=Ko(e),Pr(t,n,(function(t,n){return e(t,n[0])}))}var xa=Mo(_a),Oa=Mo(ba);function Sa(t){return null==t?[]:Ce(t,_a(t))}var ka=Ao((function(t,e,n){return e=e.toLowerCase(),t+(n?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=Ao((function(t,e,n){return t+(n?"-":"")+e.toLowerCase()})),Ia=Ao((function(t,e,n){return t+(n?" ":"")+e.toLowerCase()})),Ra=Fo("toLowerCase");var Ba=Ao((function(t,e,n){return t+(n?"_":"")+e.toLowerCase()}));var La=Ao((function(t,e,n){return t+(n?" ":"")+Ma(e)}));var Ta=Ao((function(t,e,n){return t+(n?" ":"")+e.toUpperCase()})),Ma=Fo("toUpperCase");function Wa(t,e,n){return t=aa(t),void 0===(e=n?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=Tr((function(t,e){try{return ie(t,void 0,e)}catch(n){return Mu(n)?n:new pt(n)}})),za=Go((function(t,e){return ae(e,(function(e){e=ji(e),Hn(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 wr("function"==typeof t?t:Zn(t,1))}var Qa=Tr((function(t,e){return function(n){return mr(n,t,e)}})),Ja=Tr((function(t,e){return function(n){return mr(t,n,e)}}));function Za(t,e,n){var r=_a(e),o=fr(e,r);null!=n||$u(e)&&(o.length||!r.length)||(n=e,e=t,t=this,o=fr(e,_a(e)));var i=!($u(n)&&"chain"in n&&!n.chain),u=Wu(t);return ae(o,(function(n){var r=e[n];t[n]=r,u&&(t.prototype[n]=function(){var e=this.__chain__;if(i||e){var n=t(this.__wrapped__),o=n.__actions__=mo(this.__actions__);return o.push({func:r,args:arguments,thisArg:t}),n.__chain__=e,n}return r.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)?Ae(ji(t)):function(t){return function(e){return sr(e,t)}}(t)}var nc=Io(),rc=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 On.after=function(t,e){if("function"!=typeof e)throw new mt(i);return t=ra(t),function(){if(--t<1)return e.apply(this,arguments)}},On.ary=yu,On.assign=ca,On.assignIn=la,On.assignInWith=fa,On.assignWith=sa,On.at=pa,On.before=gu,On.bind=mu,On.bindAll=za,On.bindKey=Du,On.castArray=function(){if(!arguments.length)return[];var t=arguments[0];return Pu(t)?t:[t]},On.chain=eu,On.chunk=function(t,e,n){e=(n?ci(t,e,n):void 0===e)?1:un(ra(e),0);var o=null==t?0:t.length;if(!o||e<1)return[];for(var i=0,u=0,a=r(Ye(o/e));io?0:o+n),(r=void 0===r||r>o?o:ra(r))<0&&(r+=o),r=n>r?0:oa(r);n>>0)?(t=aa(t))&&("string"==typeof e||null!=e&&!Qu(e))&&!(e=Kr(e))&&Me(t)?lo(Ve(t),0,n):t.split(e,n):[]},On.spread=function(t,e){if("function"!=typeof t)throw new mt(i);return e=null==e?0:un(ra(e),0),Tr((function(n){var r=n[e],o=lo(n,0,e);return r&&de(o,r),ie(t,this,o)}))},On.tail=function(t){var e=null==t?0:t.length;return e?Gr(t,1,e):[]},On.take=function(t,e,n){return t&&t.length?Gr(t,0,(e=n||void 0===e?1:ra(e))<0?0:e):[]},On.takeRight=function(t,e,n){var r=null==t?0:t.length;return r?Gr(t,(e=r-(e=n||void 0===e?1:ra(e)))<0?0:e,r):[]},On.takeRightWhile=function(t,e){return t&&t.length?eo(t,Ko(e,3),!1,!0):[]},On.takeWhile=function(t,e){return t&&t.length?eo(t,Ko(e,3)):[]},On.tap=function(t,e){return e(t),t},On.throttle=function(t,e,n){var r=!0,o=!0;if("function"!=typeof t)throw new mt(i);return $u(n)&&(r="leading"in n?!!n.leading:r,o="trailing"in n?!!n.trailing:o),_u(t,e,{leading:r,maxWait:e,trailing:o})},On.thru=nu,On.toArray=ea,On.toPairs=xa,On.toPairsIn=Oa,On.toPath=function(t){return Pu(t)?ve(t,ji):Ku(t)?[t]:mo(Ai(aa(t)))},On.toPlainObject=ua,On.transform=function(t,e,n){var r=Pu(t),o=r||Lu(t)||Yu(t);if(e=Ko(e,4),null==n){var i=t&&t.constructor;n=o?r?new i:[]:$u(t)&&Wu(i)?Sn(Gt(t)):{}}return(o?ae:cr)(t,(function(t,r,o){return e(n,t,r,o)})),n},On.unary=function(t){return yu(t,1)},On.union=qi,On.unionBy=Gi,On.unionWith=Vi,On.uniq=function(t){return t&&t.length?Yr(t):[]},On.uniqBy=function(t,e){return t&&t.length?Yr(t,Ko(e,2)):[]},On.uniqWith=function(t,e){return e="function"==typeof e?e:void 0,t&&t.length?Yr(t,void 0,e):[]},On.unset=function(t,e){return null==t||Xr(t,e)},On.unzip=Hi,On.unzipWith=Qi,On.update=function(t,e,n){return null==t?t:to(t,e,uo(n))},On.updateWith=function(t,e,n,r){return r="function"==typeof r?r:void 0,null==t?t:to(t,e,uo(n),r)},On.values=Sa,On.valuesIn=function(t){return null==t?[]:Ce(t,ba(t))},On.without=Ji,On.words=Wa,On.wrap=function(t,e){return ju(uo(e),t)},On.xor=Zi,On.xorBy=Ki,On.xorWith=Yi,On.zip=Xi,On.zipObject=function(t,e){return oo(t||[],e||[],$n)},On.zipObjectDeep=function(t,e){return oo(t||[],e||[],Ur)},On.zipWith=tu,On.entries=xa,On.entriesIn=Oa,On.extend=la,On.extendWith=fa,Za(On,On),On.add=uc,On.attempt=Ua,On.camelCase=ka,On.capitalize=Ca,On.ceil=ac,On.clamp=function(t,e,n){return void 0===n&&(n=e,e=void 0),void 0!==n&&(n=(n=ia(n))==n?n:0),void 0!==e&&(e=(e=ia(e))==e?e:0),Jn(ia(t),e,n)},On.clone=function(t){return Zn(t,4)},On.cloneDeep=function(t){return Zn(t,5)},On.cloneDeepWith=function(t,e){return Zn(t,5,e="function"==typeof e?e:void 0)},On.cloneWith=function(t,e){return Zn(t,4,e="function"==typeof e?e:void 0)},On.conformsTo=function(t,e){return null==e||Kn(t,e,_a(e))},On.deburr=Na,On.defaultTo=function(t,e){return null==t||t!=t?e:t},On.divide=cc,On.endsWith=function(t,e,n){t=aa(t),e=Kr(e);var r=t.length,o=n=void 0===n?r:Jn(ra(n),0,r);return(n-=e.length)>=0&&t.slice(n,o)==e},On.eq=Su,On.escape=function(t){return(t=aa(t))&&M.test(t)?t.replace(L,Le):t},On.escapeRegExp=function(t){return(t=aa(t))&&H.test(t)?t.replace(V,"\\$&"):t},On.every=function(t,e,n){var r=Pu(t)?le:nr;return n&&ci(t,e,n)&&(e=void 0),r(t,Ko(e,3))},On.find=iu,On.findIndex=Ni,On.findKey=function(t,e){return De(t,Ko(e,3),cr)},On.findLast=uu,On.findLastIndex=Pi,On.findLastKey=function(t,e){return De(t,Ko(e,3),lr)},On.floor=lc,On.forEach=au,On.forEachRight=cu,On.forIn=function(t,e){return null==t?t:ur(t,Ko(e,3),ba)},On.forInRight=function(t,e){return null==t?t:ar(t,Ko(e,3),ba)},On.forOwn=function(t,e){return t&&cr(t,Ko(e,3))},On.forOwnRight=function(t,e){return t&&lr(t,Ko(e,3))},On.get=ha,On.gt=ku,On.gte=Cu,On.has=function(t,e){return null!=t&&oi(t,e,hr)},On.hasIn=ya,On.head=Ri,On.identity=Va,On.includes=function(t,e,n,r){t=Ru(t)?t:Sa(t),n=n&&!r?ra(n):0;var o=t.length;return n<0&&(n=un(o+n,0)),Zu(t)?n<=o&&t.indexOf(e,n)>-1:!!o&&be(t,e,n)>-1},On.indexOf=function(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var o=null==n?0:ra(n);return o<0&&(o=un(r+o,0)),be(t,e,o)},On.inRange=function(t,e,n){return e=na(e),void 0===n?(n=e,e=0):n=na(n),function(t,e,n){return t>=an(e,n)&&t=-9007199254740991&&t<=9007199254740991},On.isSet=Ju,On.isString=Zu,On.isSymbol=Ku,On.isTypedArray=Yu,On.isUndefined=function(t){return void 0===t},On.isWeakMap=function(t){return qu(t)&&ri(t)==E},On.isWeakSet=function(t){return qu(t)&&"[object WeakSet]"==vr(t)},On.join=function(t,e){return null==t?"":rn.call(t,e)},On.kebabCase=Pa,On.last=Mi,On.lastIndexOf=function(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var o=r;return void 0!==n&&(o=(o=ra(n))<0?un(r+o,0):an(o,r-1)),e==e?function(t,e,n){for(var r=n+1;r--;)if(t[r]===e)return r;return r}(t,e,o):_e(t,we,o,!0)},On.lowerCase=Ia,On.lowerFirst=Ra,On.lt=Xu,On.lte=ta,On.max=function(t){return t&&t.length?rr(t,Va,dr):void 0},On.maxBy=function(t,e){return t&&t.length?rr(t,Ko(e,2),dr):void 0},On.mean=function(t){return Fe(t,Va)},On.meanBy=function(t,e){return Fe(t,Ko(e,2))},On.min=function(t){return t&&t.length?rr(t,Va,jr):void 0},On.minBy=function(t,e){return t&&t.length?rr(t,Ko(e,2),jr):void 0},On.stubArray=oc,On.stubFalse=ic,On.stubObject=function(){return{}},On.stubString=function(){return""},On.stubTrue=function(){return!0},On.multiply=sc,On.nth=function(t,e){return t&&t.length?Cr(t,ra(e)):void 0},On.noConflict=function(){return Ht._===this&&(Ht._=St),this},On.noop=Ka,On.now=hu,On.pad=function(t,e,n){t=aa(t);var r=(e=ra(e))?Ge(t):0;if(!e||r>=e)return t;var o=(e-r)/2;return Po(Xe(o),n)+t+Po(Ye(o),n)},On.padEnd=function(t,e,n){t=aa(t);var r=(e=ra(e))?Ge(t):0;return e&&re){var r=t;t=e,e=r}if(n||t%1||e%1){var o=fn();return an(t+o*(e-t+$t("1e-"+((o+"").length-1))),e)}return Br(t,e)},On.reduce=function(t,e,n){var r=Pu(t)?he:xe,o=arguments.length<3;return r(t,Ko(e,4),n,o,tr)},On.reduceRight=function(t,e,n){var r=Pu(t)?ye:xe,o=arguments.length<3;return r(t,Ko(e,4),n,o,er)},On.repeat=function(t,e,n){return e=(n?ci(t,e,n):void 0===e)?1:ra(e),Lr(aa(t),e)},On.replace=function(){var t=arguments,e=aa(t[0]);return t.length<3?e:e.replace(t[1],t[2])},On.result=function(t,e,n){var r=-1,o=(e=ao(e,t)).length;for(o||(o=1,t=void 0);++r9007199254740991)return[];var n=4294967295,r=an(t,4294967295);t-=4294967295;for(var o=Se(r,e=Ko(e));++n=i)return t;var a=n-Ge(r);if(a<1)return r;var c=u?lo(u,0,a).join(""):t.slice(0,a);if(void 0===o)return c+r;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(rt.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(Kr(o),a)!=a){var p=c.lastIndexOf(o);p>-1&&(c=c.slice(0,p))}return c+r},On.unescape=function(t){return(t=aa(t))&&T.test(t)?t.replace(B,He):t},On.uniqueId=function(t){var e=++At;return aa(t)+e},On.upperCase=Ta,On.upperFirst=Ma,On.each=au,On.eachRight=cu,On.first=Ri,Za(On,(fc={},cr(On,(function(t,e){Ft.call(On.prototype,e)||(fc[e]=t)})),fc),{chain:!1}),On.VERSION="4.17.15",ae(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(t){On[t].placeholder=On})),ae(["drop","take"],(function(t,e){Nn.prototype[t]=function(n){n=void 0===n?1:un(ra(n),0);var r=this.__filtered__&&!e?new Nn(this):this.clone();return r.__filtered__?r.__takeCount__=an(n,r.__takeCount__):r.__views__.push({size:an(n,4294967295),type:t+(r.__dir__<0?"Right":"")}),r},Nn.prototype[t+"Right"]=function(e){return this.reverse()[t](e).reverse()}})),ae(["filter","map","takeWhile"],(function(t,e){var n=e+1,r=1==n||3==n;Nn.prototype[t]=function(t){var e=this.clone();return e.__iteratees__.push({iteratee:Ko(t,3),type:n}),e.__filtered__=e.__filtered__||r,e}})),ae(["head","last"],(function(t,e){var n="take"+(e?"Right":"");Nn.prototype[t]=function(){return this[n](1).value()[0]}})),ae(["initial","tail"],(function(t,e){var n="drop"+(e?"":"Right");Nn.prototype[t]=function(){return this.__filtered__?new Nn(this):this[n](1)}})),Nn.prototype.compact=function(){return this.filter(Va)},Nn.prototype.find=function(t){return this.filter(t).head()},Nn.prototype.findLast=function(t){return this.reverse().find(t)},Nn.prototype.invokeMap=Tr((function(t,e){return"function"==typeof t?new Nn(this):this.map((function(n){return mr(n,t,e)}))})),Nn.prototype.reject=function(t){return this.filter(Fu(Ko(t)))},Nn.prototype.slice=function(t,e){t=ra(t);var n=this;return n.__filtered__&&(t>0||e<0)?new Nn(n):(t<0?n=n.takeRight(-t):t&&(n=n.drop(t)),void 0!==e&&(n=(e=ra(e))<0?n.dropRight(-e):n.take(e-t)),n)},Nn.prototype.takeRightWhile=function(t){return this.reverse().takeWhile(t).reverse()},Nn.prototype.toArray=function(){return this.take(4294967295)},cr(Nn.prototype,(function(t,e){var n=/^(?:filter|find|map|reject)|While$/.test(e),r=/^(?:head|last)$/.test(e),o=On[r?"take"+("last"==e?"Right":""):e],i=r||/^find/.test(e);o&&(On.prototype[e]=function(){var e=this.__wrapped__,u=r?[1]:arguments,a=e instanceof Nn,c=u[0],l=a||Pu(e),f=function(t){var e=o.apply(On,de([t],u));return r&&s?e[0]:e};l&&n&&"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 Nn(this);var h=t.apply(e,u);return h.__actions__.push({func:nu,args:[f],thisArg:void 0}),new Cn(h,s)}return v&&d?t.apply(this,u):(h=this.thru(f),v?r?h.value()[0]:h.value():h)})})),ae(["pop","push","shift","sort","splice","unshift"],(function(t){var e=Dt[t],n=/^(?:push|sort|unshift)$/.test(t)?"tap":"thru",r=/^(?:pop|shift)$/.test(t);On.prototype[t]=function(){var t=arguments;if(r&&!this.__chain__){var o=this.value();return e.apply(Pu(o)?o:[],t)}return this[n]((function(n){return e.apply(Pu(n)?n:[],t)}))}})),cr(Nn.prototype,(function(t,e){var n=On[e];if(n){var r=n.name+"";Ft.call(Dn,r)||(Dn[r]=[]),Dn[r].push({name:e,func:n})}})),Dn[So(void 0,2).name]=[{name:"wrapper",func:void 0}],Nn.prototype.clone=function(){var t=new Nn(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},Nn.prototype.reverse=function(){if(this.__filtered__){var t=new Nn(this);t.__dir__=-1,t.__filtered__=!0}else(t=this.clone()).__dir__*=-1;return t},Nn.prototype.value=function(){var t=this.__wrapped__.value(),e=this.__dir__,n=Pu(t),r=e<0,o=n?t.length:0,i=function(t,e,n){var r=-1,o=n.length;for(;++r=this.__values__.length;return{done:t,value:t?void 0:this.__values__[this.__index__++]}},On.prototype.plant=function(t){for(var e,n=this;n instanceof kn;){var r=Oi(n);r.__index__=0,r.__values__=void 0,e?o.__wrapped__=r:e=r;var o=r;n=n.__wrapped__}return o.__wrapped__=t,e},On.prototype.reverse=function(){var t=this.__wrapped__;if(t instanceof Nn){var e=t;return this.__actions__.length&&(e=new Nn(this)),(e=e.reverse()).__actions__.push({func:nu,args:[$i],thisArg:void 0}),new Cn(e,this.__chain__)}return this.thru($i)},On.prototype.toJSON=On.prototype.valueOf=On.prototype.value=function(){return no(this.__wrapped__,this.__actions__)},On.prototype.first=On.prototype.head,Yt&&(On.prototype[Yt]=function(){return this}),On}();Ht._=Qe,void 0===(o=function(){return Qe}.call(e,n,e,r))||(r.exports=o)}).call(this)}).call(this,n(76),n(482)(t))},480:function(t,e,n){"use strict";var r=n(0),o=Object(r.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});e.a=o},481:function(t,e,n){"use strict";n.d(e,"a",(function(){return i}));n(77),n(499),n(464),n(78);var r=n(501),o=n.n(r);function i(t,e){var n=new o.a;return t.map((function(t){var r=t;return"string"==typeof t&&(r={label:t,permalink:"/blog/tags/"+n.slug(t)}),function(t,e){var n=t.label.split(": ",2),r=n[0],o=n[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"}}(r)}return{category:r,count:t.count,label:t.label,permalink:t.permalink,style:i,value:o}}(r,e)}))}},482: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}},491:function(t,e,n){var r=n(30),o=n(54),i=n(27),u=n(26),a=n(492);t.exports=function(t,e){var n=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=r(a,d,3),_=u(m.length),b=0,E=n?v(e,_):c?v(e,0):void 0;_>b;b++)if((p||b in m)&&(y=D(h=m[b],b,g),t))if(n)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}}},492:function(t,e,n){var r=n(493);t.exports=function(t,e){return new(r(t))(e)}},493:function(t,e,n){var r=n(13),o=n(494),i=n(2)("species");t.exports=function(t){var e;return o(t)&&("function"!=typeof(e=t.constructor)||e!==Array&&!o(e.prototype)||(e=void 0),r(e)&&null===(e=e[i])&&(e=void 0)),void 0===e?Array:e}},494:function(t,e,n){var r=n(23);t.exports=Array.isArray||function(t){return"Array"==r(t)}},495:function(t,e,n){"use strict";var r=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=n(533)(),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%":r,"%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=n(496),g=n(536),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,A=function(t){var e=b(t,0,1),n=b(t,-1);if("%"===e&&"%"!==n)throw new r("invalid intrinsic syntax, expected closing `%`");if("%"===n&&"%"!==e)throw new r("invalid intrinsic syntax, expected opening `%`");var o=[];return _(t,w,(function(t,e,n,r){o[o.length]=n?_(r,F,"$1"):e||t})),o},j=function(t,e){var n,o=t;if(g(h,o)&&(o="%"+(n=h[o])[0]+"%"),g(d,o)){var a=d[o];if(a===p&&(a=function t(e){var n;if("%AsyncFunction%"===e)n=u("async function () {}");else if("%GeneratorFunction%"===e)n=u("function* () {}");else if("%AsyncGeneratorFunction%"===e)n=u("async function* () {}");else if("%AsyncGenerator%"===e){var r=t("%AsyncGeneratorFunction%");r&&(n=r.prototype)}else if("%AsyncIteratorPrototype%"===e){var o=t("%AsyncGenerator%");o&&(n=s(o.prototype))}return d[e]=n,n}(o)),void 0===a&&!e)throw new i("intrinsic "+t+" exists, but is not available. Please file an issue!");return{alias:n,name:o,value:a}}throw new r("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 r("`%` may not be present anywhere but at the beginning and end of the intrinsic name");var n=A(t),o=n.length>0?n[0]:"",u=j("%"+o+"%",e),c=u.name,l=u.value,f=!1,s=u.alias;s&&(o=s[0],D(n,m([0,1],s)));for(var p=1,v=!0;p=n.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}},496:function(t,e,n){"use strict";var r=n(535);t.exports=Function.prototype.bind||r},497:function(t,e,n){"use strict";var r=String.prototype.replace,o=/%20/g,i="RFC1738",u="RFC3986";t.exports={default:u,formatters:{RFC1738:function(t){return r.call(t,o,"+")},RFC3986:function(t){return String(t)}},RFC1738:i,RFC3986:u}},500:function(t,e,n){"use strict";var r=n(0),o=n.n(r),i=n(456),u=n(449),a=n.n(u);e.a=function(t){var e=t.count,n=t.label,r=t.permalink,u=t.style,c=t.value,l=t.valueOnly;return o.a.createElement(i.a,{to:r+"/",className:a()("badge","badge--rounded","badge--"+u)},l?c:n,e&&o.a.createElement(o.a.Fragment,null," (",e,")"))}},501:function(t,e,n){var r=n(502);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(r(),"").replace(i,"-"))}a.prototype.slug=function(t,e){for(var n=c(t,!0===e),r=n;o.call(this.occurrences,n);)this.occurrences[r]++,n=r+"-"+this.occurrences[r];return this.occurrences[n]=0,n},a.prototype.reset=function(){this.occurrences=Object.create(null)},a.slug=c},502: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}},504:function(t,e,n){"use strict";var r=n(497),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 n=e&&e.plainObjects?Object.create(null):{},r=0;r1;){var e=t.pop(),n=e.obj[e.prop];if(i(n)){for(var r=[],o=0;o=48&&f<=57||f>=65&&f<=90||f>=97&&f<=122||i===r.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 n=[],r=0;r0?A.join(",")||null:void 0}];else if(c(v))I=v;else{var B=Object.keys(A);I=y?B.sort(y):B}for(var L=u&&c(A)&&1===A.length?n+"[]":n,T=0;T0?b+_:""}},532:function(t,e,n){"use strict";var r=n(495),o=n(537),i=n(539),u=r("%TypeError%"),a=r("%WeakMap%",!0),c=r("%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 n,r=t;null!==(n=r.next);r=n)if(n.key===e)return r.next=n.next,n.next=t.next,t.next=n,n};t.exports=function(){var t,e,n,r={assert:function(t){if(!r.has(t))throw new u("Side channel does not contain "+i(t))},get:function(r){if(a&&r&&("object"==typeof r||"function"==typeof r)){if(t)return l(t,r)}else if(c){if(e)return p(e,r)}else if(n)return function(t,e){var n=h(t,e);return n&&n.value}(n,r)},has:function(r){if(a&&r&&("object"==typeof r||"function"==typeof r)){if(t)return s(t,r)}else if(c){if(e)return d(e,r)}else if(n)return function(t,e){return!!h(t,e)}(n,r);return!1},set:function(r,o){a&&r&&("object"==typeof r||"function"==typeof r)?(t||(t=new a),f(t,r,o)):c?(e||(e=new c),v(e,r,o)):(n||(n={key:{},next:null}),function(t,e,n){var r=h(t,e);r?r.value=n:t.next={key:e,next:t.next,value:n}}(n,r,o))}};return r}},533:function(t,e,n){"use strict";var r="undefined"!=typeof Symbol&&Symbol,o=n(534);t.exports=function(){return"function"==typeof r&&("function"==typeof Symbol&&("symbol"==typeof r("foo")&&("symbol"==typeof Symbol("bar")&&o())))}},534:function(t,e,n){"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"),n=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(n))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 r=Object.getOwnPropertySymbols(t);if(1!==r.length||r[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}},535:function(t,e,n){"use strict";var r="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(r+e);for(var n,u=o.call(arguments,1),a=function(){if(this instanceof n){var r=e.apply(this,u.concat(o.call(arguments)));return Object(r)===r?r:this}return e.apply(t,u.concat(o.call(arguments)))},c=Math.max(0,e.length-u.length),l=[],f=0;f-1?o(n):n}},538:function(t,e,n){"use strict";var r=n(496),o=n(495),i=o("%Function.prototype.apply%"),u=o("%Function.prototype.call%"),a=o("%Reflect.apply%",!0)||r.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(r,u,arguments);if(c&&l){var n=c(e,"length");n.configurable&&l(e,"length",{value:1+f(0,t.length-(arguments.length-1))})}return e};var s=function(){return a(r,i,arguments)};l?l(t.exports,"apply",{value:s}):t.exports.apply=s},539:function(t,e,n){var r="function"==typeof Map&&Map.prototype,o=Object.getOwnPropertyDescriptor&&r?Object.getOwnPropertyDescriptor(Map.prototype,"size"):null,i=r&&o&&"function"==typeof o.get?o.get:null,u=r&&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,A=Array.prototype.slice,j=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 n=/[0-9](?=(?:[0-9]{3})+(?![0-9]))/g;if("number"==typeof t){var r=t<0?-j(-t):j(t);if(r!==t){var o=String(r),i=m.call(e,o.length+1);return D.call(o,n,"$&_")+"."+D.call(D.call(i,/([0-9]{3})/g,"$&_"),/_$/,"")}}return D.call(e,n,"$&_")}var R=n(540),B=R.custom,L=z(B)?B:null;function T(t,e,n){var r="double"===(n.quoteStyle||e)?'"':"'";return r+t+r}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,n,r,o){var a=n||{};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,n){if(e.length>n.maxStringLength){var r=e.length-n.maxStringLength,o="... "+r+" more character"+(r>1?"s":"");return t(m.call(e,0,n.maxStringLength),n)+o}return T(D.call(D.call(e,/(['\\])/g,"\\$1"),/[\x00-\x1f]/g,H),"single",n)}(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 j=void 0===a.depth?5:a.depth;if(void 0===r&&(r=0),r>=j&&j>0&&"object"==typeof e)return W(e)?"[Array]":"[Object]";var O=function(t,e){var n;if("\t"===t.indent)n="\t";else{if(!("number"==typeof t.indent&&t.indent>0))return null;n=F.call(Array(t.indent+1)," ")}return{base:n,prev:F.call(Array(e+1),n)}}(a,r);if(void 0===o)o=[];else if(V(o,e)>=0)return"[Circular]";function B(e,n,i){if(n&&(o=A.call(o)).push(n),i){var u={depth:a.depth};return q(a,"quoteStyle")&&(u.quoteStyle=a.quoteStyle),t(e,u,r+1,o)}return t(e,a,r+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)),nt=e.attributes||[],rt=0;rt"}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:j-r});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,n){ut.push(B(n,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(n){}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 n=0,r=t.length;n-1?t.split(","):t},l=function(t,e,n,r){if(t){var i=n.allowDots?t.replace(/\.([^.[]+)/g,"[$1]"):t,u=/(\[[^[\]]*])/g,a=n.depth>0&&/(\[[^[\]]*])/.exec(i),l=a?i.slice(0,a.index):i,f=[];if(l){if(!n.plainObjects&&o.call(Object.prototype,l)&&!n.allowPrototypes)return;f.push(l)}for(var s=0;n.depth>0&&null!==(a=u.exec(i))&&s=0;--i){var u,a=t[i];if("[]"===a&&n.parseArrays)u=[].concat(o);else{u=n.plainObjects?Object.create(null):{};var l="["===a.charAt(0)&&"]"===a.charAt(a.length-1)?a.slice(1,-1):a,f=parseInt(l,10);n.parseArrays||""!==l?!isNaN(f)&&a!==l&&String(f)===l&&f>=0&&n.parseArrays&&f<=n.arrayLimit?(u=[])[f]=o:"__proto__"!==l&&(u[l]=o):u={0:o}}o=u}return o}(f,e,n,r)}};t.exports=function(t,e){var n=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||r.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 n.plainObjects?Object.create(null):{};for(var f="string"==typeof t?function(t,e){var n,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(n=0;n-1&&(y=i(y)?[y]:y),o.call(l,h)?l[h]=r.combine(l[h],y):l[h]=y}return l}(t,n):t,s=n.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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var o=n(0),r=n.n(o),i=n(448);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)}},455:function(e,t,n){"use strict";var o=n(459),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("&"):""}},456:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(447),n(455)),a=n.n(i);n(133);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"),"."))}},459: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.4dcb1281.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 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(451)),a=n(458),c=n(450),l=n(455),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 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 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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var o=n(0),r=n.n(o),i=n(450);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)}},457:function(e,t,n){"use strict";var o=n(461),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("&"):""}},458:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(449),n(457)),a=n.n(i);n(133);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"),"."))}},461: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/c8dfbbe7.06849eb0.js.LICENSE.txt b/c7bfb1d3.4dcb1281.js.LICENSE.txt similarity index 100% rename from c8dfbbe7.06849eb0.js.LICENSE.txt rename to c7bfb1d3.4dcb1281.js.LICENSE.txt diff --git a/c8223350.276e6f38.js b/c8223350.59ecc0ce.js similarity index 93% rename from c8223350.276e6f38.js rename to c8223350.59ecc0ce.js index e6198e9c17..dfb9fbaecb 100644 --- a/c8223350.276e6f38.js +++ b/c8223350.59ecc0ce.js @@ -1,2 +1,2 @@ -/*! For license information please see c8223350.276e6f38.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 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(449)),i=n(456),c=n(448),l=n(453),u=(n(457),{last_modified_on:"2024-07-12",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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"},"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)("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 Network")),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},454:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(458),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}))}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},457:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(454),i=n(447),c=n.n(i);n(134);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)}},458:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},459: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.59ecc0ce.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 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(451)),i=n(458),c=n(450),l=n(455),u=(n(459),{last_modified_on:"2024-07-12",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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"},"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)("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 Network")),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},456:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(460),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}))}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},459:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(456),i=n(449),c=n.n(i);n(134);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)}},460:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},461: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.22e76592.js.LICENSE.txt b/c8223350.59ecc0ce.js.LICENSE.txt similarity index 100% rename from cbb976f4.22e76592.js.LICENSE.txt rename to c8223350.59ecc0ce.js.LICENSE.txt diff --git a/c8dfbbe7.06849eb0.js b/c8dfbbe7.669b5289.js similarity index 96% rename from c8dfbbe7.06849eb0.js rename to c8dfbbe7.669b5289.js index 9095516f1c..a3d743c12e 100644 --- a/c8dfbbe7.06849eb0.js +++ b/c8dfbbe7.669b5289.js @@ -1,2 +1,2 @@ -/*! For license information please see c8dfbbe7.06849eb0.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 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),c=(n(0),n(449)),o=(n(456),n(448)),i=(n(453),{last_modified_on:"2023-12-30",title:"Infrastructure",description:"Understand how Qovery deploys your infrastructure on AWS"}),s={id:"getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure",title:"Infrastructure",description:"Understand how Qovery deploys your infrastructure on AWS",source:"@site/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure.md",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure",sidebar:"docs",previous:{title:"Create Credentials",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials"},next:{title:"FAQ",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/faq"}},l=[{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:[]}],u={rightToc:l};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(c.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),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(r.a)({parentName:"tr"},{align:null}),"Network Services"),Object(c.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Optional"),Object(c.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"A dedicated multi AZ VPC"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"Subnets, routing tables, subnet groups and security groups for RDS (multi AZ)"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Dedicated network fand security rules for RDS")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Subnets, routing tables, subnet groups and security groups for DocumentDB (multi AZ)"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Dedicated network fand security rules for DocumentDB")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Subnets, routing tables, subnet groups and security groups for Elasticache (multi AZ)"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Dedicated network fand security rules for Elasticache")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"An internet gateway for the VPC"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Required to let containers having access to Internet")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Dedicated NLB to redirect 443 traffic to Nginx Ingress"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"NAT gateways (multi AZ) + EIP addresses (multi AZ) + subnet groups + routing table"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"yes"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Useful to get outgoing static IP")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Dedicated VPC routes for VPC peering"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"yes"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"Kubernetes Services"),Object(c.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Optional"),Object(c.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"A dedicated EKS cluster (multi AZ) for this VPC"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"IAM dedicated user for AWS EBS CSI to access EC2 volumes + a dedicated policy"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"IAM dedicated user for AWS IAM User Sync + a dedicated policy"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"IAM dedicated user for a Cluster Autoscaler+ a dedicated policy"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"IAM dedicated policies for AWS EKS CNI, EC2 container registry + EKS worker nodes"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"Security group for EKS remote access (dual authentication: TLS + IAM authenticator)"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"Security group for 443 port pointing to Nginx ingress inside EKS"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"Other Services"),Object(c.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Optional"),Object(c.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Cloudwatch log groups for the EKS cluster"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"Dedicated S3 bucket for application's logs + a dedicated IAM account"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Application's logs are stored in an KMS encrypted S3 private bucket")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Dedicated S3 bucket to store the kubeconfig"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Kubernetes Kubeconfig is stored in an KMS encrypted, private and versioned 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)(o.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)(o.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\nby yourself by following the guide "I don\'t have Qovery access anymore, how could I delete Qovery deployed resources on my AWS account?"\nin ',Object(c.b)("a",Object(r.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)(o.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\nreflect 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\ncharacters)."),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(r.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(r.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'))))}b.isMDXComponent=!0},447: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 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)},d={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,c=e.originalType,o=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),b=u(n),p=r,m=b["".concat(o,".").concat(p)]||b[p]||d[p]||c;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 c=n.length,o=new Array(c);o[0]=p;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 l=2;l1?arguments[1]:void 0,n),s=o>2?arguments[2]:void 0,l=void 0===s?n:a(s,n);l>i;)t[i++]=e;return t}},452:function(e,t,n){var r=n(28).f,a=Function.prototype,c=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(c)[1]}catch(e){return""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),c=n(448);t.a=function(e){var t=e.children,n=e.name;return a.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"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},455:function(e,t,n){"use strict";var r=n(459),a=n(51);function c(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(),c=t.length>0?t.join("="):void 0;c=void 0===c?null:decodeURIComponent(c),n(decodeURIComponent(a),c,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?[c(t,e),"[",r,"]"].join(""):[c(t,e),"[",c(r,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=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 c(r,t);if(Array.isArray(a)){var o=[];return a.slice().forEach((function(e){void 0!==e&&o.push(n(r,e,o.length))})),o.join("&")}return c(r,t)+"="+c(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),c=(n(447),n(455)),o=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.headingDepth,c=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?"+o.a.stringify(s),u=Object(r.useState)(null),b=u[0],d=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!c&&!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 d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:l,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"),"."))}},459: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 c8dfbbe7.669b5289.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 l})),n.d(t,"default",(function(){return b}));var r=n(1),a=n(9),c=(n(0),n(451)),o=(n(458),n(450)),i=(n(455),{last_modified_on:"2023-12-30",title:"Infrastructure",description:"Understand how Qovery deploys your infrastructure on AWS"}),s={id:"getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure",title:"Infrastructure",description:"Understand how Qovery deploys your infrastructure on AWS",source:"@site/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure.md",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure",sidebar:"docs",previous:{title:"Create Credentials",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials"},next:{title:"FAQ",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/faq"}},l=[{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:[]}],u={rightToc:l};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(c.b)("wrapper",Object(r.a)({},u,n,{components:t,mdxType:"MDXLayout"}),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(r.a)({parentName:"tr"},{align:null}),"Network Services"),Object(c.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Optional"),Object(c.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"A dedicated multi AZ VPC"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"Subnets, routing tables, subnet groups and security groups for RDS (multi AZ)"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Dedicated network fand security rules for RDS")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Subnets, routing tables, subnet groups and security groups for DocumentDB (multi AZ)"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Dedicated network fand security rules for DocumentDB")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Subnets, routing tables, subnet groups and security groups for Elasticache (multi AZ)"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Dedicated network fand security rules for Elasticache")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"An internet gateway for the VPC"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Required to let containers having access to Internet")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Dedicated NLB to redirect 443 traffic to Nginx Ingress"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"NAT gateways (multi AZ) + EIP addresses (multi AZ) + subnet groups + routing table"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"yes"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Useful to get outgoing static IP")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Dedicated VPC routes for VPC peering"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"yes"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"Kubernetes Services"),Object(c.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Optional"),Object(c.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"A dedicated EKS cluster (multi AZ) for this VPC"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"IAM dedicated user for AWS EBS CSI to access EC2 volumes + a dedicated policy"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"IAM dedicated user for AWS IAM User Sync + a dedicated policy"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"IAM dedicated user for a Cluster Autoscaler+ a dedicated policy"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"IAM dedicated policies for AWS EKS CNI, EC2 container registry + EKS worker nodes"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"Security group for EKS remote access (dual authentication: TLS + IAM authenticator)"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"Security group for 443 port pointing to Nginx ingress inside EKS"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"Other Services"),Object(c.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Optional"),Object(c.b)("th",Object(r.a)({parentName:"tr"},{align:null}),"Description"))),Object(c.b)("tbody",{parentName:"table"},Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Cloudwatch log groups for the EKS cluster"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.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(r.a)({parentName:"tr"},{align:null}),"Dedicated S3 bucket for application's logs + a dedicated IAM account"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Application's logs are stored in an KMS encrypted S3 private bucket")),Object(c.b)("tr",{parentName:"tbody"},Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Dedicated S3 bucket to store the kubeconfig"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"no"),Object(c.b)("td",Object(r.a)({parentName:"tr"},{align:null}),"Kubernetes Kubeconfig is stored in an KMS encrypted, private and versioned 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)(o.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)(o.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\nby yourself by following the guide "I don\'t have Qovery access anymore, how could I delete Qovery deployed resources on my AWS account?"\nin ',Object(c.b)("a",Object(r.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)(o.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\nreflect 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\ncharacters)."),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(r.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(r.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'))))}b.isMDXComponent=!0},449: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 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)},d={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,c=e.originalType,o=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),b=u(n),p=r,m=b["".concat(o,".").concat(p)]||b[p]||d[p]||c;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 c=n.length,o=new Array(c);o[0]=p;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 l=2;l1?arguments[1]:void 0,n),s=o>2?arguments[2]:void 0,l=void 0===s?n:a(s,n);l>i;)t[i++]=e;return t}},454:function(e,t,n){var r=n(28).f,a=Function.prototype,c=/^\s*function ([^ (]*)/;"name"in a||n(10)&&r(a,"name",{configurable:!0,get:function(){try{return(""+this).match(c)[1]}catch(e){return""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),c=n(450);t.a=function(e){var t=e.children,n=e.name;return a.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"},a.a.createElement("p",{class:"text--lg margin-bottom--sm",style:{marginTop:"-0.25em"}},"Before you begin, this ",n||"page"," assumes the following:"),t)}},457:function(e,t,n){"use strict";var r=n(461),a=n(51);function c(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(),c=t.length>0?t.join("="):void 0;c=void 0===c?null:decodeURIComponent(c),n(decodeURIComponent(a),c,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?[c(t,e),"[",r,"]"].join(""):[c(t,e),"[",c(r,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=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 c(r,t);if(Array.isArray(a)){var o=[];return a.slice().forEach((function(e){void 0!==e&&o.push(n(r,e,o.length))})),o.join("&")}return c(r,t)+"="+c(a,t)})).filter((function(e){return e.length>0})).join("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),c=(n(449),n(457)),o=n.n(c);n(133);t.a=function(e){var t=e.children,n=e.headingDepth,c=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?"+o.a.stringify(s),u=Object(r.useState)(null),b=u[0],d=u[1];return a.a.createElement("div",{className:"steps steps--h"+n},t,!c&&!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 d("yes")}},"Yes"),"\xa0\xa0",a.a.createElement("a",{href:l,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"),"."))}},461: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.a834be8b.js.LICENSE.txt b/c8dfbbe7.669b5289.js.LICENSE.txt similarity index 100% rename from cbcbf0e3.a834be8b.js.LICENSE.txt rename to c8dfbbe7.669b5289.js.LICENSE.txt diff --git a/cb05c8fa.b456bf53.js b/cb05c8fa.ad1d58eb.js similarity index 74% rename from cb05c8fa.b456bf53.js rename to cb05c8fa.ad1d58eb.js index 5b5ba4eb00..1f16ec885d 100644 --- a/cb05c8fa.b456bf53.js +++ b/cb05c8fa.ad1d58eb.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[233],{385:function(a){a.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"language-javascript","name":"language: javascript","count":2,"permalink":"/guides/tags/language-javascript"}')}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[235],{387:function(a){a.exports=JSON.parse('{"allTagsPath":"/guides/tags","slug":"language-javascript","name":"language: javascript","count":2,"permalink":"/guides/tags/language-javascript"}')}}]); \ No newline at end of file diff --git a/cb2208c1.0d9958e0.js b/cb2208c1.383c309b.js similarity index 95% rename from cb2208c1.0d9958e0.js rename to cb2208c1.383c309b.js index 771eae0bc7..209faaaf8e 100644 --- a/cb2208c1.0d9958e0.js +++ b/cb2208c1.383c309b.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[234],{386: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 p}));var n=r(1),o=r(9),a=(r(0),r(449)),i={last_modified_on:"2023-12-29",title:"How Qovery Works",description:"How Qovery works under the hood"},c={id:"getting-started/how-qovery-works",title:"How Qovery Works",description:"How Qovery works under the hood",source:"@site/docs/getting-started/how-qovery-works.md",permalink:"/docs/getting-started/how-qovery-works",sidebar:"docs",previous:{title:"What is Qovery?",permalink:"/docs/getting-started/what-is-qovery"},next:{title:"Basic Concepts",permalink:"/docs/getting-started/basic-concepts"}},l=[{value:"Control Plane",id:"control-plane",children:[]},{value:"Remote Agents",id:"remote-agents",children:[]}],s={rightToc:l};function p(e){var t=e.components,r=Object(o.a)(e,["components"]);return Object(a.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(a.b)("p",null,"Qovery is a service that runs on top of your Kubernetes cluster. It is composed of two main components:"),Object(a.b)("h2",{id:"control-plane"},"Control Plane"),Object(a.b)("p",null,"The control plane is the brain of Qovery. It is responsible for:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Orchestrating the lifecycle of your applications"),Object(a.b)("li",{parentName:"ul"},"Managing the access and permissions of your team members"),Object(a.b)("li",{parentName:"ul"},"Providing the API to interact with Qovery")),Object(a.b)("h2",{id:"remote-agents"},"Remote Agents"),Object(a.b)("p",null,"The remote agents are the workers of Qovery. They are responsible for:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Deploying your applications"),Object(a.b)("li",{parentName:"ul"},"Managing the lifecycle of your applications"),Object(a.b)("li",{parentName:"ul"},"Gathering metrics and logs from your applications")),Object(a.b)("p",null,"Curious to know more how Qovery works in detail? Refer to ",Object(a.b)("a",Object(n.a)({parentName:"p"},{href:"https://www.qovery.com/blog/how-we-built-qovery---part-1"}),"this article")))}p.isMDXComponent=!0},449:function(e,t,r){"use strict";r.d(t,"a",(function(){return u})),r.d(t,"b",(function(){return y}));var n=r(0),o=r.n(n);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 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||(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({}),p=function(e){var t=o.a.useContext(s),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(s.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,a=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=p(r),f=n,y=u["".concat(i,".").concat(f)]||u[f]||b[f]||a;return r?o.a.createElement(y,c({ref:t},s,{components:r})):o.a.createElement(y,c({ref:t},s))}));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]=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 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({}),p=function(e){var t=o.a.useContext(s),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(s.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,a=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=p(r),f=n,y=u["".concat(i,".").concat(f)]||u[f]||b[f]||a;return r?o.a.createElement(y,c({ref:t},s,{components:r})):o.a.createElement(y,c({ref:t},s))}));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]=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 s=2;s {\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(i.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(i.b)("inlineCode",{parentName:"p"},"3000"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/4.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"Afterwards, we need to add two environment variables:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"accessKeyId")," - your AWS access key ID"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"secretAccessKey")," - your AWS secret access key")),Object(i.b)("p",null,"You can add them in ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variebles")," ",Object(i.b)("inlineCode",{parentName:"p"},"Secret")," section in your application settings:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/5.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/6.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"After all the setup is all done, click the ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy")," button - the application will be shortly deployed."),Object(i.b)("h2",{id:"create-lambda-consumers"},"Create Lambda Consumers"),Object(i.b)("p",null,"In AWS Console, open ",Object(i.b)("inlineCode",{parentName:"p"},"AWS Lambda")," panel."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/7.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"For the sake of the guide, we will use a simple ",Object(i.b)("inlineCode",{parentName:"p"},"hello-world")," lambda from AWS serverless app repository."),Object(i.b)("p",null,"Browse the app repository and pick the ",Object(i.b)("inlineCode",{parentName:"p"},"hello-world")," function as shown in the screenshot above, and deploy the function"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/8.png",alt:"AWS SQS Lambda"})),Object(i.b)("h2",{id:"create-lambda-trigger"},"Create Lambda Trigger"),Object(i.b)("p",null,"To make our Lambdas consume messages from SQS, we will need to add a ",Object(i.b)("inlineCode",{parentName:"p"},"Lambda Trigger")," in the SQS configuration."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/9.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"Click on ",Object(i.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(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/10.png",alt:"AWS SQS Lambda"})),Object(i.b)("h2",{id:"configure-permissions"},"Configure Permissions"),Object(i.b)("p",null,"Let's now grant our Lambda functions access to the SQS queue we created before."),Object(i.b)("p",null,"In our lambda view, click on ",Object(i.b)("inlineCode",{parentName:"p"},"Configure"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/11.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"Then, click on a role in ",Object(i.b)("inlineCode",{parentName:"p"},"Execution role")," to get redirected to a view where we can alter our Lambda permissions."),Object(i.b)("p",null,"In the role summary screen, click on ",Object(i.b)("inlineCode",{parentName:"p"},"Edit policy")," next to ",Object(i.b)("inlineCode",{parentName:"p"},"helloWorldrolePolicy")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/12.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"In the ",Object(i.b)("inlineCode",{parentName:"p"},"SQS")," section, grant permissions to all Read/Write options in the ",Object(i.b)("inlineCode",{parentName:"p"},"Actions")," ",Object(i.b)("inlineCode",{parentName:"p"},"Access level")," and accept the changes:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/13.png",alt:"AWS SQS Lambda"})),Object(i.b)("h2",{id:"test-lambda-as-an-sqs-consumer-flow"},"Test Lambda as an SQS Consumer Flow"),Object(i.b)("p",null,"To push messages to our SQS queue from the backend app deployed on Qovery, click on the ",Object(i.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(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/14.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"Now, in the ",Object(i.b)("inlineCode",{parentName:"p"},"Monitoring")," section of SQS in AWS Console, we will see messages received on metrics charts:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/15.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"To validate that our consumer Lambdas processed the messages, navigate to your lambda ",Object(i.b)("inlineCode",{parentName:"p"},"Monitor")," panel:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/16.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"In the ",Object(i.b)("inlineCode",{parentName:"p"},"Invocations")," chart, you'll notice that our Lambda was triggered several times by the messages sent over the SQS."),Object(i.b)("h2",{id:"conclusions"},"Conclusions"),Object(i.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},447: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 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)},m={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,i=e.originalType,o=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=b(n),d=a,p=u["".concat(o,".").concat(d)]||u[d]||m[d]||i;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 i=n.length,o=new Array(i);o[0]=d;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,o[1]=s;for(var l=2;l1?arguments[1]:void 0,n),c=o>2?arguments[2]:void 0,l=void 0===c?n:r(c,n);l>s;)t[s++]=e;return t}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),i=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),i=n.n(r),o=n(39),s=n(458),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),m=Object(r.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,u]),b&&u?i.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(b),m.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})):i.a.createElement("a",Object(a.a)({},e,{href:b}))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),i=n(454),o=n(447),s=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.className,a=e.badge,o=e.leftIcon,c=e.rightIcon,l=e.size,b=e.target,u=e.to,m=s()("jump-to","jump-to--"+l,n),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):"",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:m},d):r.a.createElement(i.a,{to:u,className:m},d)}},458: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.0dc6efbc.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[237],{389:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return o})),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),i=(n(0),n(451)),o=(n(450),n(455),n(459),{last_modified_on:"2023-12-30",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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(i.b)("wrapper",Object(a.a)({},l,n,{components:t,mdxType:"MDXLayout"}),Object(i.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(i.b)("inlineCode",{parentName:"p"},"Amazon SQS"),") to build a highly scalable backend."),Object(i.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(i.b)("h2",{id:"goal"},"Goal"),Object(i.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(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"We will use ",Object(i.b)("inlineCode",{parentName:"li"},"AWS Lambda")," to process events from the queue in a serverless way"),Object(i.b)("li",{parentName:"ul"},"We will use Qovery-managed backend application workers to process events from the queue")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/1.png",alt:"AWS SQS Lambda"})),Object(i.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(i.b)("p",null,"The backend application and workers servers that consume messages from the queue will be fully managed and deployed by Qovery."),Object(i.b)("p",null,"Let's get started."),Object(i.b)("h2",{id:"configure-sqs"},"Configure SQS"),Object(i.b)("p",null,"Open ",Object(i.b)("inlineCode",{parentName:"p"},"Amazon SQS")," service in AWS Console and click on ",Object(i.b)("inlineCode",{parentName:"p"},"Create Queue")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/2.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"We will use the ",Object(i.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(i.b)("inlineCode",{parentName:"p"},"Create"),"."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/3.png",alt:"AWS SQS Lambda"})),Object(i.b)("h2",{id:"create-message-producer"},"Create Message Producer"),Object(i.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(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/aws-sqs-example/blob/main/index.js"}),"here"),"."),Object(i.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(i.b)("pre",null,Object(i.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(i.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(i.b)("inlineCode",{parentName:"p"},"3000"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/4.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"Afterwards, we need to add two environment variables:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"accessKeyId")," - your AWS access key ID"),Object(i.b)("li",{parentName:"ul"},Object(i.b)("inlineCode",{parentName:"li"},"secretAccessKey")," - your AWS secret access key")),Object(i.b)("p",null,"You can add them in ",Object(i.b)("inlineCode",{parentName:"p"},"Environment Variebles")," ",Object(i.b)("inlineCode",{parentName:"p"},"Secret")," section in your application settings:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/5.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/6.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"After all the setup is all done, click the ",Object(i.b)("inlineCode",{parentName:"p"},"Deploy")," button - the application will be shortly deployed."),Object(i.b)("h2",{id:"create-lambda-consumers"},"Create Lambda Consumers"),Object(i.b)("p",null,"In AWS Console, open ",Object(i.b)("inlineCode",{parentName:"p"},"AWS Lambda")," panel."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/7.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"For the sake of the guide, we will use a simple ",Object(i.b)("inlineCode",{parentName:"p"},"hello-world")," lambda from AWS serverless app repository."),Object(i.b)("p",null,"Browse the app repository and pick the ",Object(i.b)("inlineCode",{parentName:"p"},"hello-world")," function as shown in the screenshot above, and deploy the function"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/8.png",alt:"AWS SQS Lambda"})),Object(i.b)("h2",{id:"create-lambda-trigger"},"Create Lambda Trigger"),Object(i.b)("p",null,"To make our Lambdas consume messages from SQS, we will need to add a ",Object(i.b)("inlineCode",{parentName:"p"},"Lambda Trigger")," in the SQS configuration."),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/9.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"Click on ",Object(i.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(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/10.png",alt:"AWS SQS Lambda"})),Object(i.b)("h2",{id:"configure-permissions"},"Configure Permissions"),Object(i.b)("p",null,"Let's now grant our Lambda functions access to the SQS queue we created before."),Object(i.b)("p",null,"In our lambda view, click on ",Object(i.b)("inlineCode",{parentName:"p"},"Configure"),":"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/11.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"Then, click on a role in ",Object(i.b)("inlineCode",{parentName:"p"},"Execution role")," to get redirected to a view where we can alter our Lambda permissions."),Object(i.b)("p",null,"In the role summary screen, click on ",Object(i.b)("inlineCode",{parentName:"p"},"Edit policy")," next to ",Object(i.b)("inlineCode",{parentName:"p"},"helloWorldrolePolicy")),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/12.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"In the ",Object(i.b)("inlineCode",{parentName:"p"},"SQS")," section, grant permissions to all Read/Write options in the ",Object(i.b)("inlineCode",{parentName:"p"},"Actions")," ",Object(i.b)("inlineCode",{parentName:"p"},"Access level")," and accept the changes:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/13.png",alt:"AWS SQS Lambda"})),Object(i.b)("h2",{id:"test-lambda-as-an-sqs-consumer-flow"},"Test Lambda as an SQS Consumer Flow"),Object(i.b)("p",null,"To push messages to our SQS queue from the backend app deployed on Qovery, click on the ",Object(i.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(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/14.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"Now, in the ",Object(i.b)("inlineCode",{parentName:"p"},"Monitoring")," section of SQS in AWS Console, we will see messages received on metrics charts:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/15.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"To validate that our consumer Lambdas processed the messages, navigate to your lambda ",Object(i.b)("inlineCode",{parentName:"p"},"Monitor")," panel:"),Object(i.b)("p",{align:"center"},Object(i.b)("img",{src:"/img/aws-sqs-lambda-with-qovery/16.png",alt:"AWS SQS Lambda"})),Object(i.b)("p",null,"In the ",Object(i.b)("inlineCode",{parentName:"p"},"Invocations")," chart, you'll notice that our Lambda was triggered several times by the messages sent over the SQS."),Object(i.b)("h2",{id:"conclusions"},"Conclusions"),Object(i.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},449: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 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)},m={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,i=e.originalType,o=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=b(n),d=a,p=u["".concat(o,".").concat(d)]||u[d]||m[d]||i;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 i=n.length,o=new Array(i);o[0]=d;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,o[1]=s;for(var l=2;l1?arguments[1]:void 0,n),c=o>2?arguments[2]:void 0,l=void 0===c?n:r(c,n);l>s;)t[s++]=e;return t}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),i=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),i=n.n(r),o=n(39),s=n(460),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),m=Object(r.useRef)(!1),d=l.a.canUseIntersectionObserver;return Object(r.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(b),function(){d&&t&&t.disconnect()}}),[b,d,u]),b&&u?i.a.createElement(o.b,Object(a.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(b),m.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})):i.a.createElement("a",Object(a.a)({},e,{href:b}))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),i=n(456),o=n(449),s=n.n(o);n(134);t.a=function(e){var t=e.children,n=e.className,a=e.badge,o=e.leftIcon,c=e.rightIcon,l=e.size,b=e.target,u=e.to,m=s()("jump-to","jump-to--"+l,n),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):"",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:m},d):r.a.createElement(i.a,{to:u,className:m},d)}},460: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/cc3d7007.159a26d1.js.LICENSE.txt b/cbb976f4.0dc6efbc.js.LICENSE.txt similarity index 100% rename from cc3d7007.159a26d1.js.LICENSE.txt rename to cbb976f4.0dc6efbc.js.LICENSE.txt diff --git a/cbcbf0e3.8305acf5.js b/cbcbf0e3.8305acf5.js new file mode 100644 index 0000000000..303905e435 --- /dev/null +++ b/cbcbf0e3.8305acf5.js @@ -0,0 +1,2 @@ +/*! For license information please see cbcbf0e3.8305acf5.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[238],{390: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(451)),i=n(455),c=n(458),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 a DaemonSet in a Karpenter context",permalink:"/guides/advanced/deploy-daemonset-with-karpenter"}},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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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/cc9be38a.33e78987.js.LICENSE.txt b/cbcbf0e3.8305acf5.js.LICENSE.txt similarity index 100% rename from cc9be38a.33e78987.js.LICENSE.txt rename to cbcbf0e3.8305acf5.js.LICENSE.txt diff --git a/cbcbf0e3.a834be8b.js b/cbcbf0e3.a834be8b.js deleted file mode 100644 index 2e6771376a..0000000000 --- a/cbcbf0e3.a834be8b.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see cbcbf0e3.a834be8b.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 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(449)),i=n(453),c=n(456),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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/cc3d7007.159a26d1.js b/cc3d7007.66f47401.js similarity index 89% rename from cc3d7007.159a26d1.js rename to cc3d7007.66f47401.js index 30bb1344ee..d06d415221 100644 --- a/cc3d7007.159a26d1.js +++ b/cc3d7007.66f47401.js @@ -1,2 +1,2 @@ -/*! For license information please see cc3d7007.159a26d1.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[237],{389:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return s})),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(449)),c=r(457),i={last_modified_on:"2024-01-15",title:"Managed By Qovery",sidebar_label:"hidden",hide_pagination:!0},s={id:"getting-started/install-qovery/gcp/cluster-managed-by-qovery",title:"Managed By Qovery",description:"import Jump from '@site/src/components/Jump';",source:"@site/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery.md",permalink:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery",sidebar_label:"hidden",sidebar:"docs",previous:{title:"GCP",permalink:"/docs/getting-started/install-qovery/gcp"},next:{title:"Quickstart",permalink:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart"}},u=[],l={rightToc:u};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,"Don't be shy, pick the first page you want to read and start your journey with Qovery."),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart",mdxType:"Jump"},"Quickstart"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials",mdxType:"Jump"},"Create Credentials"))}p.isMDXComponent=!0},447: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({}),l=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=l(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)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),d=n,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||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]=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:n,c[1]=i;for(var u=2;u0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):o.a.createElement("a",Object(n.a)({},e,{href:l}))}},457:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(454),c=r(447),i=r.n(c);r(134);t.a=function(e){var t=e.children,r=e.className,n=e.badge,c=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,f=i()("jump-to","jump-to--"+u,r),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"},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 l?a.a.createElement("a",{href:p,target:l,className:f},d):a.a.createElement(o.a,{to:p,className:f},d)}},458: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 cc3d7007.66f47401.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[239],{391:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return s})),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(451)),c=r(459),i={last_modified_on:"2024-01-15",title:"Managed By Qovery",sidebar_label:"hidden",hide_pagination:!0},s={id:"getting-started/install-qovery/gcp/cluster-managed-by-qovery",title:"Managed By Qovery",description:"import Jump from '@site/src/components/Jump';",source:"@site/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery.md",permalink:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery",sidebar_label:"hidden",sidebar:"docs",previous:{title:"GCP",permalink:"/docs/getting-started/install-qovery/gcp"},next:{title:"Quickstart",permalink:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart"}},u=[],l={rightToc:u};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,"Don't be shy, pick the first page you want to read and start your journey with Qovery."),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart",mdxType:"Jump"},"Quickstart"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials",mdxType:"Jump"},"Create Credentials"))}p.isMDXComponent=!0},449: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({}),l=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=l(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)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),d=n,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||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]=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:n,c[1]=i;for(var u=2;u0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):o.a.createElement("a",Object(n.a)({},e,{href:l}))}},459:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(456),c=r(449),i=r.n(c);r(134);t.a=function(e){var t=e.children,r=e.className,n=e.badge,c=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,f=i()("jump-to","jump-to--"+u,r),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"},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 l?a.a.createElement("a",{href:p,target:l,className:f},d):a.a.createElement(o.a,{to:p,className:f},d)}},460: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/d2075f7f.8913c68b.js.LICENSE.txt b/cc3d7007.66f47401.js.LICENSE.txt similarity index 100% rename from d2075f7f.8913c68b.js.LICENSE.txt rename to cc3d7007.66f47401.js.LICENSE.txt diff --git a/d2397242.8c7b487e.js b/cc9be38a.1e350f04.js similarity index 90% rename from d2397242.8c7b487e.js rename to cc9be38a.1e350f04.js index 625fa224ab..369a7e974f 100644 --- a/d2397242.8c7b487e.js +++ b/cc9be38a.1e350f04.js @@ -1,2 +1,2 @@ -/*! For license information please see d2397242.8c7b487e.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 u})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return f}));var r=n(1),a=n(9),o=(n(0),n(449)),i=n(456),c=n(448),l=(n(512),n(453)),s={last_modified_on:"2024-03-01",$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",id:"install-qovery",children:[]},{value:"Deploy your first application",id:"deploy-your-first-application",children:[]}]},{value:"Next Steps",id:"next-steps",children:[]}],d={rightToc:p};function f(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://console.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.png",alt:"Qovery Sign-up page"})))),Object(o.b)("li",null,Object(o.b)("h3",{id:"install-qovery"},"Install Qovery"),Object(o.b)("p",null,"If you did not install Qovery yet, ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/"}),"follow this documentation"),".")),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!"))}f.isMDXComponent=!0},447: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)}},f=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),f=r,b=p["".concat(i,".").concat(f)]||p[f]||d[f]||o;return n?a.a.createElement(b,c({ref:t},s,{components:n})):a.a.createElement(b,c({ref:t},s))}));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]=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 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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}},512:function(e,t,n){"use strict";var r=n(0),a=n.n(r);n(448),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.1e350f04.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 s})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return f}));var r=n(1),a=n(9),o=(n(0),n(451)),i=n(458),c=n(450),l=(n(514),n(455)),s={last_modified_on:"2024-03-01",$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",id:"install-qovery",children:[]},{value:"Deploy your first application",id:"deploy-your-first-application",children:[]}]},{value:"Next Steps",id:"next-steps",children:[]}],d={rightToc:p};function f(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://console.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.png",alt:"Qovery Sign-up page"})))),Object(o.b)("li",null,Object(o.b)("h3",{id:"install-qovery"},"Install Qovery"),Object(o.b)("p",null,"If you did not install Qovery yet, ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/"}),"follow this documentation"),".")),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!"))}f.isMDXComponent=!0},449: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)}},f=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),f=r,b=p["".concat(i,".").concat(f)]||p[f]||d[f]||o;return n?a.a.createElement(b,c({ref:t},s,{components:n})):a.a.createElement(b,c({ref:t},s))}));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]=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 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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}},514:function(e,t,n){"use strict";var r=n(0),a=n.n(r);n(450),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.8c7b487e.js.LICENSE.txt b/cc9be38a.1e350f04.js.LICENSE.txt similarity index 100% rename from d2397242.8c7b487e.js.LICENSE.txt rename to cc9be38a.1e350f04.js.LICENSE.txt diff --git a/cf490432.320bd1db.js b/cf490432.317db8ee.js similarity index 96% rename from cf490432.320bd1db.js rename to cf490432.317db8ee.js index ab13bbb84b..091d33a144 100644 --- a/cf490432.320bd1db.js +++ b/cf490432.317db8ee.js @@ -1 +1 @@ -(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 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(449)),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},449: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 c5a20281bd..591b6cea54 100644 --- a/components/index.html +++ b/components/index.html @@ -24,19 +24,19 @@ - + - + - + - + - + - + - + @@ -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 6470f7645f..5c0d2cf07e 100644 --- a/contact/index.html +++ b/contact/index.html @@ -24,19 +24,19 @@ - + - + - + - + - + - + - + @@ -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/d2075f7f.8913c68b.js b/d2075f7f.db248259.js similarity index 90% rename from d2075f7f.8913c68b.js rename to d2075f7f.db248259.js index b5f6bd601a..9232e6c22d 100644 --- a/d2075f7f.8913c68b.js +++ b/d2075f7f.db248259.js @@ -1,2 +1,2 @@ -/*! For license information please see d2075f7f.8913c68b.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[240],{446: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(449)),i=t(448);t(447),t(392);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},447: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 +/*! For license information please see d2075f7f.db248259.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[242],{448: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(451)),i=t(450);t(449),t(394);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},449: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/d589d3a7.2a5b76ea.js.LICENSE.txt b/d2075f7f.db248259.js.LICENSE.txt similarity index 100% rename from d589d3a7.2a5b76ea.js.LICENSE.txt rename to d2075f7f.db248259.js.LICENSE.txt diff --git a/cc9be38a.33e78987.js b/d2397242.838b5c3e.js similarity index 90% rename from cc9be38a.33e78987.js rename to d2397242.838b5c3e.js index 67267535c5..297de55bfd 100644 --- a/cc9be38a.33e78987.js +++ b/d2397242.838b5c3e.js @@ -1,2 +1,2 @@ -/*! For license information please see cc9be38a.33e78987.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[238],{390: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 f}));var r=n(1),a=n(9),o=(n(0),n(449)),i=n(456),c=n(448),l=(n(512),n(453)),s={last_modified_on:"2024-03-01",$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",id:"install-qovery",children:[]},{value:"Deploy your first application",id:"deploy-your-first-application",children:[]}]},{value:"Next Steps",id:"next-steps",children:[]}],d={rightToc:p};function f(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://console.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.png",alt:"Qovery Sign-up page"})))),Object(o.b)("li",null,Object(o.b)("h3",{id:"install-qovery"},"Install Qovery"),Object(o.b)("p",null,"If you did not install Qovery yet, ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/"}),"follow this documentation"),".")),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!"))}f.isMDXComponent=!0},447: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)}},f=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),f=r,b=p["".concat(i,".").concat(f)]||p[f]||d[f]||o;return n?a.a.createElement(b,c({ref:t},s,{components:n})):a.a.createElement(b,c({ref:t},s))}));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]=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 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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}},512:function(e,t,n){"use strict";var r=n(0),a=n.n(r);n(448),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.838b5c3e.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 s})),n.d(t,"metadata",(function(){return u})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return f}));var r=n(1),a=n(9),o=(n(0),n(451)),i=n(458),c=n(450),l=(n(514),n(455)),s={last_modified_on:"2024-03-01",$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",id:"install-qovery",children:[]},{value:"Deploy your first application",id:"deploy-your-first-application",children:[]}]},{value:"Next Steps",id:"next-steps",children:[]}],d={rightToc:p};function f(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://console.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.png",alt:"Qovery Sign-up page"})))),Object(o.b)("li",null,Object(o.b)("h3",{id:"install-qovery"},"Install Qovery"),Object(o.b)("p",null,"If you did not install Qovery yet, ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/"}),"follow this documentation"),".")),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!"))}f.isMDXComponent=!0},449: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)}},f=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),f=r,b=p["".concat(i,".").concat(f)]||p[f]||d[f]||o;return n?a.a.createElement(b,c({ref:t},s,{components:n})):a.a.createElement(b,c({ref:t},s))}));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]=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 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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461:function(e,t,n){"use strict";e.exports=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}},514:function(e,t,n){"use strict";var r=n(0),a=n.n(r);n(450),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/d99b987c.141a5830.js.LICENSE.txt b/d2397242.838b5c3e.js.LICENSE.txt similarity index 100% rename from d99b987c.141a5830.js.LICENSE.txt rename to d2397242.838b5c3e.js.LICENSE.txt diff --git a/d28d5470.fe5477ca.js b/d28d5470.f016b4fc.js similarity index 94% rename from d28d5470.fe5477ca.js rename to d28d5470.f016b4fc.js index b30b147f2d..5a4c4a2408 100644 --- a/d28d5470.fe5477ca.js +++ b/d28d5470.f016b4fc.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[242],{394: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(449)),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},449: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||(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}))}},457:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(454),c=n(447),i=n.n(c);n(134);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)}},458: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.3d8e0967.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 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(451)),c=n(459),i={last_modified_on:"2024-06-19",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},449: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}))}},459:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(456),c=n(449),i=n.n(c);n(134);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)}},460: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/da253275.ae41bdee.js.LICENSE.txt b/d589d3a7.3d8e0967.js.LICENSE.txt similarity index 100% rename from da253275.ae41bdee.js.LICENSE.txt rename to d589d3a7.3d8e0967.js.LICENSE.txt diff --git a/d85dc1ef.0b449bdd.js b/d85dc1ef.1daeb367.js similarity index 98% rename from d85dc1ef.0b449bdd.js rename to d85dc1ef.1daeb367.js index cea8e49ecc..746f4e1eda 100644 --- a/d85dc1ef.0b449bdd.js +++ b/d85dc1ef.1daeb367.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[246],{398: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 o=n(1),r=n(9),a=(n(0),n(449)),i={last_modified_on:"2023-12-29",title:"Basic Concepts",description:"Basic Concepts about Qovery"},c={id:"getting-started/basic-concepts",title:"Basic Concepts",description:"Basic Concepts about Qovery",source:"@site/docs/getting-started/basic-concepts.md",permalink:"/docs/getting-started/basic-concepts",sidebar:"docs",previous:{title:"How Qovery Works",permalink:"/docs/getting-started/how-qovery-works"},next:{title:"Install Qovery",permalink:"/docs/getting-started/install-qovery"}},l=[{value:"Organization",id:"organization",children:[]},{value:"Cluster",id:"cluster",children:[{value:"Managed Cluster",id:"managed-cluster",children:[]},{value:"Self-Managed Cluster",id:"self-managed-cluster",children:[]}]},{value:"Project",id:"project",children:[]},{value:"Environment",id:"environment",children:[]},{value:"Preview Environment (or Ephemeral Environment)",id:"preview-environment-or-ephemeral-environment",children:[]},{value:"Service",id:"service",children:[]},{value:"Deployment",id:"deployment",children:[]},{value:"High Level Schema",id:"high-level-schema",children:[]}],s={rightToc:l};function u(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(a.b)("wrapper",Object(o.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(a.b)("h2",{id:"organization"},"Organization"),Object(a.b)("p",null,"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 ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/members-rbac/#roles-based-access-control-rbac"}),"RBAC system"),"."),Object(a.b)("p",null,"More information about ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/"}),"Organization here"),"."),Object(a.b)("h2",{id:"cluster"},"Cluster"),Object(a.b)("p",null,"At Qovery, when we refer to Cluster, we mean ",Object(a.b)("a",Object(o.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."),Object(a.b)("p",null,"More information about ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/"}),"Cluster here"),"."),Object(a.b)("h3",{id:"managed-cluster"},"Managed Cluster"),Object(a.b)("p",null,"A Managed Cluster is a Kubernetes cluster managed by Qovery. It means that Qovery will create the cluster for you and will take care of the cluster lifecycle (creation, upgrade, deletion etc..). Zero maintenance for you."),Object(a.b)("h3",{id:"self-managed-cluster"},"Self-Managed Cluster"),Object(a.b)("p",null,"A Self-Managed Cluster is a Kubernetes cluster managed by you. It means that you have to create the cluster yourself and you have to take care of the cluster lifecycle (creation, upgrade, deletion etc..). You can install Qovery on your cluster to let Qovery manage the deployment of your applications on your cluster."),Object(a.b)("h2",{id:"project"},"Project"),Object(a.b)("p",null,"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."),Object(a.b)("p",null,"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..)"),Object(a.b)("p",null,"One organization can have more than one project and you can customize the access to your project thanks to our ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/members-rbac/#roles-based-access-control-rbac"}),"RBAC system"),"."),Object(a.b)("p",null,"More information about ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/project/"}),"Project here"),"."),Object(a.b)("h2",{id:"environment"},"Environment"),Object(a.b)("p",null,"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 ",Object(a.b)("inlineCode",{parentName:"p"},"Production")," environment (all the services pointing to the main branch), one ",Object(a.b)("inlineCode",{parentName:"p"},"Staging")," environment (all services pointing to the staging branch) etc.."),Object(a.b)("p",null,"Your production environment runs 24/7 while your other environments may not need to run all day long. By setting a ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/deployment-rule/"}),"Deployment Rule")," on your environment you can automatically start/stop your non-production environments and thus reduce your cloud provider bill."),Object(a.b)("p",null,"Environments let's you chose on which cluster your services should be deployed."),Object(a.b)("p",null,"More information about ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/"}),"Environment here"),"."),Object(a.b)("h2",{id:"preview-environment-or-ephemeral-environment"},"Preview Environment (or Ephemeral Environment)"),Object(a.b)("p",null,"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."),Object(a.b)("p",null,"More information about ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#preview-environment"}),"Preview Environment here"),"."),Object(a.b)("h2",{id:"service"},"Service"),Object(a.b)("p",null,"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."),Object(a.b)("p",null,"Five types of services exists:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},'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 ',Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/application/"}),"Applications here")),Object(a.b)("li",{parentName:"ul"},"Database: it allows you to deploy a database. Qovery allows you to deploy a container and a cloud provider managed version. More information about ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/database/"}),"Databases here")),Object(a.b)("li",{parentName:"ul"},"CronJob: it allows you to deploy a cronjob on your cluster and execute it based on the selected schedule. More information about ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/cronjob/"}),"Cronjob here")),Object(a.b)("li",{parentName:"ul"},"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 ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/cronjob/"}),"Lifecycle here")),Object(a.b)("li",{parentName:"ul"},"Helm: it allows you to deploy a helm chart on your cluster. More information about ",Object(a.b)("a",Object(o.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/helm/"}),"Helm here"))),Object(a.b)("h2",{id:"deployment"},"Deployment"),Object(a.b)("p",null,"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 ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/"}),"this section"),"."),Object(a.b)("p",null,"You can monitor the execution of the deployment via the ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#deployment-logs"}),"Deployment Logs")," while you can monitor the execution of your application thanks to the streamed ",Object(a.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/#live-logs"}),"Live Logs")," directly from the Qovery interface."),Object(a.b)("h2",{id:"high-level-schema"},"High Level Schema"),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/basic_concept_orga_project_env.png",alt:"Basic Structure"})))}u.isMDXComponent=!0},449:function(e,t,n){"use strict";n.d(t,"a",(function(){return p})),n.d(t,"b",(function(){return m}));var o=n(0),r=n.n(o);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 o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function c(e){for(var t=1;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;s=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;s=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):i({},t,{},e)),r},p=function(e){var t=l(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)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),d=n,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||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]=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:n,c[1]=i;for(var u=2;u0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):o.a.createElement("a",Object(n.a)({},e,{href:l}))}},457:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(454),c=r(447),i=r.n(c);r(134);t.a=function(e){var t=e.children,r=e.className,n=e.badge,c=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,f=i()("jump-to","jump-to--"+u,r),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"},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 l?a.a.createElement("a",{href:p,target:l,className:f},d):a.a.createElement(o.a,{to:p,className:f},d)}},458: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 d99b987c.084df6b0.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[249],{401:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return s})),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(451)),c=r(459),i={last_modified_on:"2023-12-30",title:"GCP",sidebar_label:"hidden",hide_pagination:!0},s={id:"getting-started/install-qovery/gcp",title:"GCP",description:"import Jump from '@site/src/components/Jump';",source:"@site/docs/getting-started/install-qovery/gcp.md",permalink:"/docs/getting-started/install-qovery/gcp",sidebar_label:"hidden",sidebar:"docs",previous:{title:"Self-Managed Cluster",permalink:"/docs/getting-started/install-qovery/aws/self-managed-cluster"},next:{title:"Managed By Qovery",permalink:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery"}},u=[],l={rightToc:u};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,"It's a good choice. Choose your path:"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery",mdxType:"Jump"},"Cluster Managed by Qovery"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/gcp/self-managed-cluster",mdxType:"Jump"},"Self-Managed Cluster"))}p.isMDXComponent=!0},449: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({}),l=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=l(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)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),d=n,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||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]=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:n,c[1]=i;for(var u=2;u0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):o.a.createElement("a",Object(n.a)({},e,{href:l}))}},459:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(456),c=r(449),i=r.n(c);r(134);t.a=function(e){var t=e.children,r=e.className,n=e.badge,c=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,f=i()("jump-to","jump-to--"+u,r),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"},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 l?a.a.createElement("a",{href:p,target:l,className:f},d):a.a.createElement(o.a,{to:p,className:f},d)}},460: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/dab3a2be.412b34db.js.LICENSE.txt b/d99b987c.084df6b0.js.LICENSE.txt similarity index 100% rename from dab3a2be.412b34db.js.LICENSE.txt rename to d99b987c.084df6b0.js.LICENSE.txt diff --git a/d9a4c8ef.d80091ae.js b/d9a4c8ef.7c8f44b6.js similarity index 98% rename from d9a4c8ef.d80091ae.js rename to d9a4c8ef.7c8f44b6.js index df4fd1998d..669817a3de 100644 --- a/d9a4c8ef.d80091ae.js +++ b/d9a4c8ef.7c8f44b6.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[248],{400: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 p})),t.d(n,"default",(function(){return d}));var a=t(1),o=t(9),r=(t(0),t(449)),l=t(461),c=t(464),i=t(448),s={last_modified_on:"2024-05-03",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"}},p=[{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:"Pass a command",id:"pass-a-command",children:[]},{value:"Shell in a dedicated pod",id:"shell-in-a-dedicated-pod",children:[]},{value:"Shell in a dedicated container",id:"shell-in-a-dedicated-container",children:[]}]},{value:"Port-forward",id:"port-forward",children:[{value:"Port-forward a dedicated pod",id:"port-forward-a-dedicated-pod",children:[]}]},{value:"Generate API token",id:"generate-api-token",children:[]},{value:"Managing services, environments and projects",id:"managing-services-environments-and-projects",children:[{value:"Environment",id:"environment",children:[]},{value:"Projects",id:"projects",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:"Static token",id:"static-token",children:[]},{value:"Support",id:"support",children:[]}],u={rightToc:p};function d(e){var n=e.components,t=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},u,t,{components:n,mdxType:"MDXLayout"}),Object(r.b)(i.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Use Infrastructure as Code (IaC) with ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"Terraform")," and our ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/interface/rest-api/"}),"REST API")," to manage Qovery and deploy your apps.")),Object(r.b)("p",null,"Qovery provides a very easy to use CLI (Command Line Interface) designed to fit the developer workflow perfectly."),Object(r.b)("hr",null),Object(r.b)("p",null,"The purpose of the CLI is to integrate seamlessly with your development workflow:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Write code"),Object(r.b)("li",{parentName:"ol"},"Commit"),Object(r.b)("li",{parentName:"ol"},Object(r.b)("strong",{parentName:"li"},"Qovery")," - deploy a new version of your application"),Object(r.b)("li",{parentName:"ol"},Object(r.b)("strong",{parentName:"li"},"Qovery CLI")," - check the status of your application"),Object(r.b)("li",{parentName:"ol"},Object(r.b)("strong",{parentName:"li"},"Qovery CLI")," - debug your application"),Object(r.b)("li",{parentName:"ol"},"Repeat")),Object(r.b)("h2",{id:"first-usage"},"First usage"),Object(r.b)("h3",{id:"install"},"Install"),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(a.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(a.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.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(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(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(a.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(r.b)("pre",null,Object(r.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(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(a.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(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(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(a.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(r.b)("pre",null,Object(r.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(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(a.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(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(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(a.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(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/pkgs/container/qovery-cli"}),"GitHub Container Registry"),"."))),Object(r.b)("h3",{id:"sign-up"},"Sign up"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"If you are using a headless (without GUI) environment, you can use the following command to sign up and sign in:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.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 Qovery sign-up page will open. Follow the instructions to sign up and sign in."),Object(r.b)("h3",{id:"help"},"Help"),Object(r.b)("p",null,"You can see all the commands available by executing:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery help\n")),Object(r.b)("pre",null,Object(r.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 cluster Manage clusters\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 helm Manage helms\n help Help about any command\n lifecycle Manage lifecycle jobs\n list-pods List the pods of a service with their pods\n log Print your application logs\n port-forward Port forward a port to an application container\n project Manage Project\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 --verbose Verbose output\n\nUse "qovery [command] --help" for more information about a command.\n')),Object(r.b)("h2",{id:"context"},"Context"),Object(r.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(r.b)("inlineCode",{parentName:"p"},"qovery context set")," command."),Object(r.b)("p",null,"Most of the commands support an inline context set allowing you to directly pass the URL of the application you wants to interact with."),Object(r.b)("p",null,"Example:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery shell https://console.qovery.com/organization/51927012-8377-4e0f-84cf-7f5f38a0154b/project/a6545d50-69a3-4966-89cc-4c0bfb6d3448/environment/c9ac549b-a855-4d3b-b652-d68d5f1fea11/application/820ca0a3-08bf-42c1-8ad2-540714ad657f/general\n# this is the url of my back-end application\n\nOrganization | My orga\nProject | R&D / Backend\nEnvironment | prod\nServiceLevel | back-end\nServiceType | application\n\n$ ls\n...\n")),Object(r.b)("h3",{id:"set-new-context"},"Set New Context"),Object(r.b)("p",null,"To set a new context, type ",Object(r.b)("inlineCode",{parentName:"p"},"qovery context set"),":"),Object(r.b)("pre",null,Object(r.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(r.b)("h3",{id:"print-current-context"},"Print Current Context"),Object(r.b)("pre",null,Object(r.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(r.b)("h2",{id:"log"},"Log"),Object(r.b)("p",null,"Log command allows you to display the application logs."),Object(r.b)("pre",null,Object(r.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(r.b)("p",null,"By default, the last 1000 logs is displayed."),Object(r.b)("h3",{id:"follow-logs"},"Follow Logs"),Object(r.b)("p",null,"To make the CLI follow your logs, use ",Object(r.b)("inlineCode",{parentName:"p"},"-f")," flag:"),Object(r.b)("pre",null,Object(r.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(r.b)("p",null,"This will make the CLI follow your application logs and append any new logs till you use ",Object(r.b)("inlineCode",{parentName:"p"},"CTRL+C"),"."),Object(r.b)("h2",{id:"status"},"Status"),Object(r.b)("p",null,"Status command lets you print the basic status of your application."),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery status\n15 Jul 21 10:55 CEST\nApplication | Backend\nStatus | RUNNING\n")),Object(r.b)("h2",{id:"console"},"Console"),Object(r.b)("p",null,"Console command quickly opens the Qovery Console in your browser to let you display more information about your application."),Object(r.b)("pre",null,Object(r.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(r.b)("h2",{id:"shell"},"Shell"),Object(r.b)("p",null,"Shell command allows you to open a connection and execute commands directly on the container running application."),Object(r.b)("pre",null,Object(r.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(r.b)(i.a,{type:"info",mdxType:"Alert"},"Keep in mind these limitations when using this feature:",Object(r.b)("ul",null,Object(r.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(r.b)("li",null,"shell is force closed after [1 hour, 1GB transmitted];"),Object(r.b)("li",null,"we use SH by default. To have auto-completion, start bash."))),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},"The width of the terminal is limited to 80 characters. But you can resize it once you are inside the application with one of these commands:",Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"COLUMNS=200 tput init\nstty cols 200\n"))),Object(r.b)("h3",{id:"pass-a-command"},"Pass a command"),Object(r.b)("p",null,"To pass a command, you can use the ",Object(r.b)("inlineCode",{parentName:"p"},"--command")," or ",Object(r.b)("inlineCode",{parentName:"p"},"-c")," argument followed by your command."),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery shell --command 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(r.b)("p",null,"To pass several arguments, you can separate them with a comma or send different ",Object(r.b)("inlineCode",{parentName:"p"},"--command"),"."),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"qovery shell --command ls --command -l"),"\n",Object(r.b)("inlineCode",{parentName:"p"},"qovery shell --command ls,-l"),"\n",Object(r.b)("inlineCode",{parentName:"p"},"qovery shell -c ls,-l")),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery shell --command ls --command -l\ndrwxr-xr-x 2 root root 4096 Nov 30 09:32 bin\ndrwxr-xr-x 5 root root 360 Dec 21 09:46 dev\ndrwxr-xr-x 1 root root 41 Dec 20 20:13 docker-entrypoint.d\n-rwxr-xr-x 1 root root 1620 Dec 20 20:13 docker-entrypoint.sh\ndrwxr-xr-x 1 root root 25 Dec 21 09:46 etc\ndrwxr-xr-x 2 root root 6 Nov 30 09:32 home\ndrwxr-xr-x 1 root root 61 Dec 20 22:11 lib\ndrwxr-xr-x 5 root root 44 Nov 30 09:32 media\ndrwxr-xr-x 2 root root 6 Nov 30 09:32 mnt\ndrwxr-xr-x 2 root root 6 Nov 30 09:32 opt\ndr-xr-xr-x 209 root root 0 Dec 21 09:46 proc\ndrwx------ 1 root root 26 Dec 21 10:38 root\ndrwxr-xr-x 1 root root 23 Dec 21 09:46 run\ndrwxr-xr-x 2 root root 4096 Nov 30 09:32 sbin\ndrwxr-xr-x 2 root root 6 Nov 30 09:32 srv\ndr-xr-xr-x 13 root root 0 Dec 21 09:46 sys\ndrwxrwxrwt 2 root root 6 Nov 30 09:32 tmp\ndrwxr-xr-x 1 root root 66 Nov 30 09:32 usr\ndrwxr-xr-x 1 root root 19 Nov 30 09:32 var\ndrwxr-xr-x 2 root root 59 Dec 21 09:45 www\n")),Object(r.b)("h3",{id:"shell-in-a-dedicated-pod"},"Shell in a dedicated pod"),Object(r.b)("p",null,"If your application is running on several pods, you can shell directly in a dedicated one by using the ",Object(r.b)("inlineCode",{parentName:"p"},"--pod")," or ",Object(r.b)("inlineCode",{parentName:"p"},"-p")," argument followed by your pod name."),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery shell --pod app-5f65fb5c4-frontend-5f65db5c4b-q4w11\n")),Object(r.b)("p",null,"NOTE: you can get the list of pods by running the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery list-pods")," command."),Object(r.b)("h3",{id:"shell-in-a-dedicated-container"},"Shell in a dedicated container"),Object(r.b)("p",null,"If you have several containers in your pod, you can shell directly in a dedicated one by using the ",Object(r.b)("inlineCode",{parentName:"p"},"--container")," argument followed by your container name."),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery shell --container app-5f65fb5c4-frontend\n")),Object(r.b)("h2",{id:"port-forward"},"Port-forward"),Object(r.b)("p",null,"Port-forward command allows you to port-forward all the traffic on your local machine to a remote resource available on a Qovery environment. This mechanism allows developers to create a secure, encrypted tunnel from their local machine to the application or databases hosted in the cloud. "),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'$ qovery port-forward -p 8000:80 #your_local_port:your_remote_port\nInfo: Current context:\nOrganization | Qovery Prod\nProject | R&D / Frontend\nEnvironment | prod\nService | console\nType | application\n\nInfo: Continue with port-forward command using this context ?\nPlease type "yes" to validate context: yes\n\nListening on 127.0.0.1:8000 => 80\n')),Object(r.b)("p",null,"The port-forward feature works with any ",Object(r.b)("inlineCode",{parentName:"p"},"application"),", ",Object(r.b)("inlineCode",{parentName:"p"},"Cronjob"),", ",Object(r.b)("inlineCode",{parentName:"p"},"Lifecycle job")," or ",Object(r.b)("inlineCode",{parentName:"p"},"database")," (Container or Managed) deployed with Qovery. For ",Object(r.b)("inlineCode",{parentName:"p"},"Managed database")," instances on AWS, once the port-forwarded is activated, you must specify ~ ",Object(r.b)("inlineCode",{parentName:"p"},"--tls")," and ",Object(r.b)("inlineCode",{parentName:"p"},"--tls-insecure")," in your database connection command since localhost is not the valid hostname."),Object(r.b)("h3",{id:"port-forward-a-dedicated-pod"},"Port-forward a dedicated pod"),Object(r.b)("p",null,"If your application is running on several pods, you can port-forward to a dedicated one by using the ",Object(r.b)("inlineCode",{parentName:"p"},"--pod")," argument followed by your pod name."),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery port-forward -p 8000:80 -pod app-5f65fb5c4-frontend-5f65db5c4b-q4w11\n")),Object(r.b)("p",null,"NOTE: you can get the list of pods by running the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery list-pods")," command."),Object(r.b)("h2",{id:"generate-api-token"},"Generate API token"),Object(r.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(r.b)(i.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Never share your API token with anyone.")),Object(r.b)("pre",null,Object(r.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(r.b)("p",null,"To use your token and list your organizations."),Object(r.b)("pre",null,Object(r.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(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.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(r.b)("p",null,"Check out our ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://api-doc.qovery.com"}),"API documentation")),Object(r.b)("h2",{id:"managing-services-environments-and-projects"},"Managing services, environments and projects"),Object(r.b)("p",null,"The CLI allows you to manage and deploy the environment and services within your organization"),Object(r.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(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"cancel: Cancel the service deployment"),Object(r.b)("li",{parentName:"ul"},"delete: Delete a service"),Object(r.b)("li",{parentName:"ul"},"deploy: Deploy a service"),Object(r.b)("li",{parentName:"ul"},"list: List the service of the specified type"),Object(r.b)("li",{parentName:"ul"},"redeploy: Redeploy a service (already deployed before)"),Object(r.b)("li",{parentName:"ul"},"stop: Stop a service"),Object(r.b)("li",{parentName:"ul"},"update: Update a service (service name, git branch, auto-deploy, ...)")),Object(r.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(r.b)("p",null,"Example: Listing applications and triggering a deployment"),Object(r.b)("pre",null,Object(r.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(r.b)("p",null,"Example: Enable the auto-deploy feature for an application"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery application update --application backend --auto-deploy true\nApplication backend updated!\n")),Object(r.b)("h3",{id:"environment"},"Environment"),Object(r.b)("p",null,"The command ",Object(r.b)("inlineCode",{parentName:"p"},"environment")," allow you to manage a specific environment via the CLI. You can run the following actions on environments:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"cancel: Cancel an environment deployment"),Object(r.b)("li",{parentName:"ul"},"clone: Clone an environment"),Object(r.b)("li",{parentName:"ul"},"delete: Delete an environment"),Object(r.b)("li",{parentName:"ul"},"deploy: Deploy an environment"),Object(r.b)("li",{parentName:"ul"},"list: List environments"),Object(r.b)("li",{parentName:"ul"},"redeploy: Redeploy an environment"),Object(r.b)("li",{parentName:"ul"},"stage: Manage deployment stages"),Object(r.b)("li",{parentName:"ul"},"stop: Stop an environment")),Object(r.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(r.b)("p",null,"Example: Manage deployment stages and triggering deployment"),Object(r.b)("pre",null,Object(r.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(r.b)("h3",{id:"projects"},"Projects"),Object(r.b)("p",null,"You can list the organization's projects by using the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery project list\n")),Object(r.b)("h2",{id:"managing-the-deployment-pipeline"},"Managing the Deployment Pipeline"),Object(r.b)("p",null,"In the following sections we will describe how to modify the Deployment Pipeline. "),Object(r.b)("h3",{id:"list-stages"},"List stages"),Object(r.b)("p",null,"You can list all the stages of your environment by using the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage list\n")),Object(r.b)("h3",{id:"add-a-stage"},"Add a stage"),Object(r.b)("p",null,"You can add a new stage by using the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage create -n -d \n")),Object(r.b)("p",null,"Note that the stage will be added at the end of the pipeline (the highest number)"),Object(r.b)("h3",{id:"modify-a-stage"},"Modify a stage"),Object(r.b)("p",null,"You can modify a stage by using the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage edit -n --new-name --new-description \n")),Object(r.b)("h3",{id:"delete-a-stage"},"Delete a stage"),Object(r.b)("p",null,"You can modify a stage by using the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage delete -n \n")),Object(r.b)("h3",{id:"change-stage-for-a-service"},"Change stage for a service"),Object(r.b)("p",null,"You can modify the stage associated to a service by using the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage move -n --stage \n")),Object(r.b)("h2",{id:"static-token"},"Static token"),Object(r.b)("p",null,"You can use a static token to authenticate to Qovery CLI. Which is useful for CI/CD pipelines."),Object(r.b)("p",null,"Environment variables available to set static token:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"QOVERY_CLI_ACCESS_TOKEN")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"Q_CLI_ACCESS_TOKEN"))),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"export QOVERY_CLI_ACCESS_TOKEN=xxx\n\nqovery log --organization MyOrg --project MyProject --environment MyEnv --application MyApp\n# you will see the log output\n")),Object(r.b)("h2",{id:"support"},"Support"),Object(r.b)("p",null,"Do you have any issues with Qovery CLI? ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/issues"}),"Open an issue"),"."))}d.isMDXComponent=!0},448:function(e,n,t){"use strict";t(450);var a=t(0),o=t.n(a),r=t(447),l=t.n(r);t(132);n.a=function(e){var n=e.children,t=e.classNames,a=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()(t,"alert","alert--"+c,{"alert--fill":a,"alert--icon":!1!==r}),role:"alert"},!1!==r&&o.a.createElement("i",{className:l()("feather","icon-"+(r||i))}),n)}},461:function(e,n,t){"use strict";var a=t(1),o=(t(465),t(462),t(52),t(29),t(22),t(21),t(0)),r=t.n(o),l=t(469),c=t(447),i=t.n(c),s=t(455),b=t.n(s),p=t(468),u=37,d=39;function m(e){var n=e.block,t=e.centered,a=e.changeSelectedValue,o=e.className,l=e.handleKeydown,c=e.style,s=e.values,b=e.selectedValue,p=e.tabRefs;return r.a.createElement("div",{className:t?"tabs--centered":null},r.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 r.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 p.push(e)},onKeyDown:function(e){return l(p,e.target,e)},onFocus:function(){return a(n)},onClick:function(){return a(n)}},t)}))))}function h(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 r.a.createElement(l.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,l=e.groupId,c=e.label,i=e.placeholder,s=e.select,y=e.size,O=(e.style,e.values),g=e.urlKey,j=Object(p.a)(),v=j.tabGroupChoices,f=j.setTabGroupChoices,N=Object(o.useState)(t),w=N[0],x=N[1];if(null!=l){var C=v[l];null!=C&&C!==w&&x(C)}var T=function(e){x(e),null!=l&&f(l,e)},I=[],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 u:!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&&g){var e=b.a.parse(window.location.search);e[g]&&x(e[g])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(y||"md")},c&&r.a.createElement("div",{className:"margin-vert--sm"},c),O.length>1&&(s?r.a.createElement(h,Object(a.a)({changeSelectedValue:T,handleKeydown:k,placeholder:i,selectedValue:w,size:y,tabRefs:I},e)):r.a.createElement(m,Object(a.a)({changeSelectedValue:T,handleKeydown:k,selectedValue:w,tabRefs:I},e)))),o.Children.toArray(n).filter((function(e){return e.props.value===w}))[0])}},464: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([[250],{402: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 p})),t.d(n,"default",(function(){return d}));var a=t(1),o=t(9),r=(t(0),t(451)),l=t(463),c=t(466),i=t(450),s={last_modified_on:"2024-05-03",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"}},p=[{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:"Pass a command",id:"pass-a-command",children:[]},{value:"Shell in a dedicated pod",id:"shell-in-a-dedicated-pod",children:[]},{value:"Shell in a dedicated container",id:"shell-in-a-dedicated-container",children:[]}]},{value:"Port-forward",id:"port-forward",children:[{value:"Port-forward a dedicated pod",id:"port-forward-a-dedicated-pod",children:[]}]},{value:"Generate API token",id:"generate-api-token",children:[]},{value:"Managing services, environments and projects",id:"managing-services-environments-and-projects",children:[{value:"Environment",id:"environment",children:[]},{value:"Projects",id:"projects",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:"Static token",id:"static-token",children:[]},{value:"Support",id:"support",children:[]}],u={rightToc:p};function d(e){var n=e.components,t=Object(o.a)(e,["components"]);return Object(r.b)("wrapper",Object(a.a)({},u,t,{components:n,mdxType:"MDXLayout"}),Object(r.b)(i.a,{type:"success",mdxType:"Alert"},Object(r.b)("p",null,"Use Infrastructure as Code (IaC) with ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/integration/terraform/"}),"Terraform")," and our ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/interface/rest-api/"}),"REST API")," to manage Qovery and deploy your apps.")),Object(r.b)("p",null,"Qovery provides a very easy to use CLI (Command Line Interface) designed to fit the developer workflow perfectly."),Object(r.b)("hr",null),Object(r.b)("p",null,"The purpose of the CLI is to integrate seamlessly with your development workflow:"),Object(r.b)("ol",null,Object(r.b)("li",{parentName:"ol"},"Write code"),Object(r.b)("li",{parentName:"ol"},"Commit"),Object(r.b)("li",{parentName:"ol"},Object(r.b)("strong",{parentName:"li"},"Qovery")," - deploy a new version of your application"),Object(r.b)("li",{parentName:"ol"},Object(r.b)("strong",{parentName:"li"},"Qovery CLI")," - check the status of your application"),Object(r.b)("li",{parentName:"ol"},Object(r.b)("strong",{parentName:"li"},"Qovery CLI")," - debug your application"),Object(r.b)("li",{parentName:"ol"},"Repeat")),Object(r.b)("h2",{id:"first-usage"},"First usage"),Object(r.b)("h3",{id:"install"},"Install"),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(a.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(a.a)({parentName:"p"},{href:"https://aur.archlinux.org/packages"}),"AUR")," packages, so you can install it with ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Jguer/yay"}),"yay"),":"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.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(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(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(a.a)({parentName:"p"},{href:"https://brew.sh/"}),"Homebrew"),"."),Object(r.b)("pre",null,Object(r.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(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(a.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(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(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(a.a)({parentName:"p"},{href:"https://scoop.sh/"}),"Scoop"),"."),Object(r.b)("pre",null,Object(r.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(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(a.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(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(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(a.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(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/pkgs/container/qovery-cli"}),"GitHub Container Registry"),"."))),Object(r.b)("h3",{id:"sign-up"},"Sign up"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"# Sign up and sign in command\n$ qovery auth\n")),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.b)("p",null,"If you are using a headless (without GUI) environment, you can use the following command to sign up and sign in:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.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 Qovery sign-up page will open. Follow the instructions to sign up and sign in."),Object(r.b)("h3",{id:"help"},"Help"),Object(r.b)("p",null,"You can see all the commands available by executing:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery help\n")),Object(r.b)("pre",null,Object(r.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 cluster Manage clusters\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 helm Manage helms\n help Help about any command\n lifecycle Manage lifecycle jobs\n list-pods List the pods of a service with their pods\n log Print your application logs\n port-forward Port forward a port to an application container\n project Manage Project\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 --verbose Verbose output\n\nUse "qovery [command] --help" for more information about a command.\n')),Object(r.b)("h2",{id:"context"},"Context"),Object(r.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(r.b)("inlineCode",{parentName:"p"},"qovery context set")," command."),Object(r.b)("p",null,"Most of the commands support an inline context set allowing you to directly pass the URL of the application you wants to interact with."),Object(r.b)("p",null,"Example:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery shell https://console.qovery.com/organization/51927012-8377-4e0f-84cf-7f5f38a0154b/project/a6545d50-69a3-4966-89cc-4c0bfb6d3448/environment/c9ac549b-a855-4d3b-b652-d68d5f1fea11/application/820ca0a3-08bf-42c1-8ad2-540714ad657f/general\n# this is the url of my back-end application\n\nOrganization | My orga\nProject | R&D / Backend\nEnvironment | prod\nServiceLevel | back-end\nServiceType | application\n\n$ ls\n...\n")),Object(r.b)("h3",{id:"set-new-context"},"Set New Context"),Object(r.b)("p",null,"To set a new context, type ",Object(r.b)("inlineCode",{parentName:"p"},"qovery context set"),":"),Object(r.b)("pre",null,Object(r.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(r.b)("h3",{id:"print-current-context"},"Print Current Context"),Object(r.b)("pre",null,Object(r.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(r.b)("h2",{id:"log"},"Log"),Object(r.b)("p",null,"Log command allows you to display the application logs."),Object(r.b)("pre",null,Object(r.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(r.b)("p",null,"By default, the last 1000 logs is displayed."),Object(r.b)("h3",{id:"follow-logs"},"Follow Logs"),Object(r.b)("p",null,"To make the CLI follow your logs, use ",Object(r.b)("inlineCode",{parentName:"p"},"-f")," flag:"),Object(r.b)("pre",null,Object(r.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(r.b)("p",null,"This will make the CLI follow your application logs and append any new logs till you use ",Object(r.b)("inlineCode",{parentName:"p"},"CTRL+C"),"."),Object(r.b)("h2",{id:"status"},"Status"),Object(r.b)("p",null,"Status command lets you print the basic status of your application."),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery status\n15 Jul 21 10:55 CEST\nApplication | Backend\nStatus | RUNNING\n")),Object(r.b)("h2",{id:"console"},"Console"),Object(r.b)("p",null,"Console command quickly opens the Qovery Console in your browser to let you display more information about your application."),Object(r.b)("pre",null,Object(r.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(r.b)("h2",{id:"shell"},"Shell"),Object(r.b)("p",null,"Shell command allows you to open a connection and execute commands directly on the container running application."),Object(r.b)("pre",null,Object(r.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(r.b)(i.a,{type:"info",mdxType:"Alert"},"Keep in mind these limitations when using this feature:",Object(r.b)("ul",null,Object(r.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(r.b)("li",null,"shell is force closed after [1 hour, 1GB transmitted];"),Object(r.b)("li",null,"we use SH by default. To have auto-completion, start bash."))),Object(r.b)(i.a,{type:"info",mdxType:"Alert"},"The width of the terminal is limited to 80 characters. But you can resize it once you are inside the application with one of these commands:",Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"COLUMNS=200 tput init\nstty cols 200\n"))),Object(r.b)("h3",{id:"pass-a-command"},"Pass a command"),Object(r.b)("p",null,"To pass a command, you can use the ",Object(r.b)("inlineCode",{parentName:"p"},"--command")," or ",Object(r.b)("inlineCode",{parentName:"p"},"-c")," argument followed by your command."),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery shell --command 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(r.b)("p",null,"To pass several arguments, you can separate them with a comma or send different ",Object(r.b)("inlineCode",{parentName:"p"},"--command"),"."),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"qovery shell --command ls --command -l"),"\n",Object(r.b)("inlineCode",{parentName:"p"},"qovery shell --command ls,-l"),"\n",Object(r.b)("inlineCode",{parentName:"p"},"qovery shell -c ls,-l")),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery shell --command ls --command -l\ndrwxr-xr-x 2 root root 4096 Nov 30 09:32 bin\ndrwxr-xr-x 5 root root 360 Dec 21 09:46 dev\ndrwxr-xr-x 1 root root 41 Dec 20 20:13 docker-entrypoint.d\n-rwxr-xr-x 1 root root 1620 Dec 20 20:13 docker-entrypoint.sh\ndrwxr-xr-x 1 root root 25 Dec 21 09:46 etc\ndrwxr-xr-x 2 root root 6 Nov 30 09:32 home\ndrwxr-xr-x 1 root root 61 Dec 20 22:11 lib\ndrwxr-xr-x 5 root root 44 Nov 30 09:32 media\ndrwxr-xr-x 2 root root 6 Nov 30 09:32 mnt\ndrwxr-xr-x 2 root root 6 Nov 30 09:32 opt\ndr-xr-xr-x 209 root root 0 Dec 21 09:46 proc\ndrwx------ 1 root root 26 Dec 21 10:38 root\ndrwxr-xr-x 1 root root 23 Dec 21 09:46 run\ndrwxr-xr-x 2 root root 4096 Nov 30 09:32 sbin\ndrwxr-xr-x 2 root root 6 Nov 30 09:32 srv\ndr-xr-xr-x 13 root root 0 Dec 21 09:46 sys\ndrwxrwxrwt 2 root root 6 Nov 30 09:32 tmp\ndrwxr-xr-x 1 root root 66 Nov 30 09:32 usr\ndrwxr-xr-x 1 root root 19 Nov 30 09:32 var\ndrwxr-xr-x 2 root root 59 Dec 21 09:45 www\n")),Object(r.b)("h3",{id:"shell-in-a-dedicated-pod"},"Shell in a dedicated pod"),Object(r.b)("p",null,"If your application is running on several pods, you can shell directly in a dedicated one by using the ",Object(r.b)("inlineCode",{parentName:"p"},"--pod")," or ",Object(r.b)("inlineCode",{parentName:"p"},"-p")," argument followed by your pod name."),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery shell --pod app-5f65fb5c4-frontend-5f65db5c4b-q4w11\n")),Object(r.b)("p",null,"NOTE: you can get the list of pods by running the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery list-pods")," command."),Object(r.b)("h3",{id:"shell-in-a-dedicated-container"},"Shell in a dedicated container"),Object(r.b)("p",null,"If you have several containers in your pod, you can shell directly in a dedicated one by using the ",Object(r.b)("inlineCode",{parentName:"p"},"--container")," argument followed by your container name."),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery shell --container app-5f65fb5c4-frontend\n")),Object(r.b)("h2",{id:"port-forward"},"Port-forward"),Object(r.b)("p",null,"Port-forward command allows you to port-forward all the traffic on your local machine to a remote resource available on a Qovery environment. This mechanism allows developers to create a secure, encrypted tunnel from their local machine to the application or databases hosted in the cloud. "),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),'$ qovery port-forward -p 8000:80 #your_local_port:your_remote_port\nInfo: Current context:\nOrganization | Qovery Prod\nProject | R&D / Frontend\nEnvironment | prod\nService | console\nType | application\n\nInfo: Continue with port-forward command using this context ?\nPlease type "yes" to validate context: yes\n\nListening on 127.0.0.1:8000 => 80\n')),Object(r.b)("p",null,"The port-forward feature works with any ",Object(r.b)("inlineCode",{parentName:"p"},"application"),", ",Object(r.b)("inlineCode",{parentName:"p"},"Cronjob"),", ",Object(r.b)("inlineCode",{parentName:"p"},"Lifecycle job")," or ",Object(r.b)("inlineCode",{parentName:"p"},"database")," (Container or Managed) deployed with Qovery. For ",Object(r.b)("inlineCode",{parentName:"p"},"Managed database")," instances on AWS, once the port-forwarded is activated, you must specify ~ ",Object(r.b)("inlineCode",{parentName:"p"},"--tls")," and ",Object(r.b)("inlineCode",{parentName:"p"},"--tls-insecure")," in your database connection command since localhost is not the valid hostname."),Object(r.b)("h3",{id:"port-forward-a-dedicated-pod"},"Port-forward a dedicated pod"),Object(r.b)("p",null,"If your application is running on several pods, you can port-forward to a dedicated one by using the ",Object(r.b)("inlineCode",{parentName:"p"},"--pod")," argument followed by your pod name."),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery port-forward -p 8000:80 -pod app-5f65fb5c4-frontend-5f65db5c4b-q4w11\n")),Object(r.b)("p",null,"NOTE: you can get the list of pods by running the ",Object(r.b)("inlineCode",{parentName:"p"},"qovery list-pods")," command."),Object(r.b)("h2",{id:"generate-api-token"},"Generate API token"),Object(r.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(r.b)(i.a,{type:"warning",mdxType:"Alert"},Object(r.b)("p",null,"Never share your API token with anyone.")),Object(r.b)("pre",null,Object(r.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(r.b)("p",null,"To use your token and list your organizations."),Object(r.b)("pre",null,Object(r.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(r.b)(i.a,{type:"info",mdxType:"Alert"},Object(r.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(r.b)("p",null,"Check out our ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://api-doc.qovery.com"}),"API documentation")),Object(r.b)("h2",{id:"managing-services-environments-and-projects"},"Managing services, environments and projects"),Object(r.b)("p",null,"The CLI allows you to manage and deploy the environment and services within your organization"),Object(r.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(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"cancel: Cancel the service deployment"),Object(r.b)("li",{parentName:"ul"},"delete: Delete a service"),Object(r.b)("li",{parentName:"ul"},"deploy: Deploy a service"),Object(r.b)("li",{parentName:"ul"},"list: List the service of the specified type"),Object(r.b)("li",{parentName:"ul"},"redeploy: Redeploy a service (already deployed before)"),Object(r.b)("li",{parentName:"ul"},"stop: Stop a service"),Object(r.b)("li",{parentName:"ul"},"update: Update a service (service name, git branch, auto-deploy, ...)")),Object(r.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(r.b)("p",null,"Example: Listing applications and triggering a deployment"),Object(r.b)("pre",null,Object(r.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(r.b)("p",null,"Example: Enable the auto-deploy feature for an application"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"$ qovery application update --application backend --auto-deploy true\nApplication backend updated!\n")),Object(r.b)("h3",{id:"environment"},"Environment"),Object(r.b)("p",null,"The command ",Object(r.b)("inlineCode",{parentName:"p"},"environment")," allow you to manage a specific environment via the CLI. You can run the following actions on environments:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"cancel: Cancel an environment deployment"),Object(r.b)("li",{parentName:"ul"},"clone: Clone an environment"),Object(r.b)("li",{parentName:"ul"},"delete: Delete an environment"),Object(r.b)("li",{parentName:"ul"},"deploy: Deploy an environment"),Object(r.b)("li",{parentName:"ul"},"list: List environments"),Object(r.b)("li",{parentName:"ul"},"redeploy: Redeploy an environment"),Object(r.b)("li",{parentName:"ul"},"stage: Manage deployment stages"),Object(r.b)("li",{parentName:"ul"},"stop: Stop an environment")),Object(r.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(r.b)("p",null,"Example: Manage deployment stages and triggering deployment"),Object(r.b)("pre",null,Object(r.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(r.b)("h3",{id:"projects"},"Projects"),Object(r.b)("p",null,"You can list the organization's projects by using the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery project list\n")),Object(r.b)("h2",{id:"managing-the-deployment-pipeline"},"Managing the Deployment Pipeline"),Object(r.b)("p",null,"In the following sections we will describe how to modify the Deployment Pipeline. "),Object(r.b)("h3",{id:"list-stages"},"List stages"),Object(r.b)("p",null,"You can list all the stages of your environment by using the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage list\n")),Object(r.b)("h3",{id:"add-a-stage"},"Add a stage"),Object(r.b)("p",null,"You can add a new stage by using the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage create -n -d \n")),Object(r.b)("p",null,"Note that the stage will be added at the end of the pipeline (the highest number)"),Object(r.b)("h3",{id:"modify-a-stage"},"Modify a stage"),Object(r.b)("p",null,"You can modify a stage by using the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage edit -n --new-name --new-description \n")),Object(r.b)("h3",{id:"delete-a-stage"},"Delete a stage"),Object(r.b)("p",null,"You can modify a stage by using the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage delete -n \n")),Object(r.b)("h3",{id:"change-stage-for-a-service"},"Change stage for a service"),Object(r.b)("p",null,"You can modify the stage associated to a service by using the following command:"),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"qovery environment stage move -n --stage \n")),Object(r.b)("h2",{id:"static-token"},"Static token"),Object(r.b)("p",null,"You can use a static token to authenticate to Qovery CLI. Which is useful for CI/CD pipelines."),Object(r.b)("p",null,"Environment variables available to set static token:"),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"QOVERY_CLI_ACCESS_TOKEN")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"Q_CLI_ACCESS_TOKEN"))),Object(r.b)("pre",null,Object(r.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"export QOVERY_CLI_ACCESS_TOKEN=xxx\n\nqovery log --organization MyOrg --project MyProject --environment MyEnv --application MyApp\n# you will see the log output\n")),Object(r.b)("h2",{id:"support"},"Support"),Object(r.b)("p",null,"Do you have any issues with Qovery CLI? ",Object(r.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/Qovery/qovery-cli/issues"}),"Open an issue"),"."))}d.isMDXComponent=!0},450:function(e,n,t){"use strict";t(452);var a=t(0),o=t.n(a),r=t(449),l=t.n(r);t(132);n.a=function(e){var n=e.children,t=e.classNames,a=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()(t,"alert","alert--"+c,{"alert--fill":a,"alert--icon":!1!==r}),role:"alert"},!1!==r&&o.a.createElement("i",{className:l()("feather","icon-"+(r||i))}),n)}},463:function(e,n,t){"use strict";var a=t(1),o=(t(467),t(464),t(52),t(29),t(22),t(21),t(0)),r=t.n(o),l=t(471),c=t(449),i=t.n(c),s=t(457),b=t.n(s),p=t(470),u=37,d=39;function m(e){var n=e.block,t=e.centered,a=e.changeSelectedValue,o=e.className,l=e.handleKeydown,c=e.style,s=e.values,b=e.selectedValue,p=e.tabRefs;return r.a.createElement("div",{className:t?"tabs--centered":null},r.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 r.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 p.push(e)},onKeyDown:function(e){return l(p,e.target,e)},onFocus:function(){return a(n)},onClick:function(){return a(n)}},t)}))))}function h(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 r.a.createElement(l.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,l=e.groupId,c=e.label,i=e.placeholder,s=e.select,y=e.size,O=(e.style,e.values),g=e.urlKey,j=Object(p.a)(),v=j.tabGroupChoices,f=j.setTabGroupChoices,N=Object(o.useState)(t),w=N[0],x=N[1];if(null!=l){var C=v[l];null!=C&&C!==w&&x(C)}var T=function(e){x(e),null!=l&&f(l,e)},I=[],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 u:!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&&g){var e=b.a.parse(window.location.search);e[g]&&x(e[g])}}),[]),r.a.createElement(r.a.Fragment,null,r.a.createElement("div",{className:"margin-bottom--"+(y||"md")},c&&r.a.createElement("div",{className:"margin-vert--sm"},c),O.length>1&&(s?r.a.createElement(h,Object(a.a)({changeSelectedValue:T,handleKeydown:k,placeholder:i,selectedValue:w,size:y,tabRefs:I},e)):r.a.createElement(m,Object(a.a)({changeSelectedValue:T,handleKeydown:k,selectedValue:w,tabRefs:I},e)))),o.Children.toArray(n).filter((function(e){return e.props.value===w}))[0])}},466: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.54f0dc79.js b/d9deea5f.838b999e.js similarity index 97% rename from d9deea5f.54f0dc79.js rename to d9deea5f.838b999e.js index 5da758c07a..bc7a44c514 100644 --- a/d9deea5f.54f0dc79.js +++ b/d9deea5f.838b999e.js @@ -1,2 +1,2 @@ -/*! For license information please see d9deea5f.54f0dc79.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[249],{401:function(n,t,e){"use strict";e.r(t);var r=e(0),u=e.n(r),i=e(471),a=e(540),o=e(454);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(o.a,{to:"/guides"},"View All Guides")))),u.a.createElement("main",{className:"container container--s"},u.a.createElement(a.a,{items:e,staggered:null!=e[0].content.metadata.seriesPosition})))}},447: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")},471:function(n,t,e){"use strict";e(481);var r=e(0),u=e.n(r),i=e(482),a=e(470),o=e(1),c=(e(472),e(473),e(483),e(454)),l=e(484),f=e(466),s=e.n(f),v=e(485),h=e.n(v),d=e(460),p=e(447),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(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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),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(z,{alt:f.alt,url:v})):u.a.createElement(z,{alt:f.alt,url:v})),u.a.createElement("small",null,a),u.a.createElement("br",null))))},W=e(486),M=e(487),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,D=n.keywords,g=(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}),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)))}},474:function(n,t,e){"use strict";var r=e(9),u=e(0),i=e.n(u),a=e(447),o=e.n(a),c=e(460),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)}}},475: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]",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),H=/^\s+|\s+$/g,K=/^\s+/,J=/\s+$/,Q=/\{(?:\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]",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,Hn=Vn||Zn||Function("return this")(),Kn=t&&!t.nodeType&&t,Jn=Kn&&"object"==typeof r&&r&&!r.nodeType&&r,Qn=Jn&&Jn.exports===Kn,Yn=Qn&&Vn.process,Xn=function(){try{var n=Jn&&Jn.require&&Jn.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 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 Kt=function n(t){var e,r=(t=null==t?Hn:Kt.defaults(Hn.Object(),t,Kt.pick(Hn,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=Hn._,Nn=gn("^"+Fn.call(Cn).replace(V,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Bn=Qn?t.Buffer:void 0,Ln=t.Symbol,zn=t.Uint8Array,$n=Bn?Bn.allocUnsafe:void 0,Vn=Pt(Dn.getPrototypeOf,Dn),Zn=Dn.create,Kn=En.propertyIsEnumerable,Jn=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){}}(),Jt=t.clearTimeout!==Hn.clearTimeout&&t.clearTimeout,Qt=u&&u.now!==Hn.Date.now&&u.now,Yt=t.setTimeout!==Hn.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),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"),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($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 Je(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 gu(n,a)}else{var I=ei(n),S=I==h||I==d;if(Ra(n))return su(n,o);if(I==g||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,Ve(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 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,o)}}i||(i=new ze);var L=i.get(n);if(L)return L;i.set(n,a),Ha(n)?n.forEach((function(r){a.add(Je(r,t,e,r,n,i))})):qa(n)&&n.forEach((function(r,u){a.set(u,Je(r,t,e,u,n,i))}));var R=E?void 0:(v?l?Vu:Gu:l?bo:yo)(n);return ct(R||n,(function(r,u){R&&(r=n[u=r]),$e(a,u,Je(r,t,e,u,n,i))})),a}function Qe(n,t,e){var r=e.length;if(null==n)return!r;for(n=Dn(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=Qu(this,n).delete(n);return this.size-=t?1:0,t},Le.prototype.get=function(n){return Qu(this,n).get(n)},Le.prototype.has=function(n){return Qu(this,n).has(n)},Le.prototype.set=function(n,t){var e=Qu(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(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 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,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&&Jn.call(o,c,1),Jn.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)?Jn.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,Vo),n+"")}function Wr(n){return We(jo(n))}function Mr(n,t){var e=jo(n);return wi(e,Ke(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&&!Ja(a)&&(e?a<=t:a=200){var l=t?null:zu(n);if(l)return qt(l);a=!1,u=It,c=new Re}else c=t?[]:o;n:for(;++r=r?n:Gr(n,t,e)}var fu=Jt||function(n){return Hn.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=Ja(n),a=void 0!==t,o=null===t,c=t==t,l=Ja(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=Dn(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"==Hu(a))var o=new Ne([],!0)}for(r=o?r:e;++r1&&m.reverse(),s&&l<_&&(m.length=l),this&&this!==Hn&&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=Qr(e),r=Qr(r)):(e=Jr(e),r=Jr(r)),u=n(e,r)}return u}}function Nu(n){return qu((function(t){return t=dt(t,Nt(Ju())),Tr((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?" ":Qr(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&&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(Q,"{\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 He(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,Ju(t,3))}function oa(n,t){return(Ba(n)?lt:tr)(n,Ju(t,3))}var ca=mu((function(n,t,e){Cn.call(n,e)?n[e].push(t):Ze(n,e,[t])}));var la=Tr((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,Ju(t,3))}var va=mu((function(n,t,e){n[e?0:1].push(t)}),(function(){return[[],[]]}));var ha=Tr((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=Qt||function(){return Hn.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 Da(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 ga=Tr((function(n,t,e){var r=1;if(e.length){var u=$t(e,Ku(ga));r|=32}return Wu(n,r,t,e,u)})),_a=Tr((function(n,t,e){var r=3;if(e.length){var u=$t(e,Ku(_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(g,t),s?d(n):o}function D(n){var e=n-l;return void 0===l||e>=t||e<0||v&&n-f>=a}function g(){var n=da();if(D(n))return _(n);c=mi(g,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=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)),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=Tr((function(n,t){return Ye(n,1,t)})),ba=Tr((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(Ju())):dt(ir(t,1),Nt(Ju()))).length;return Tr((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")&&!Kn.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,za=tt?Nt(tt):function(n){return $a(n)&&hr(n)==s};function Ta(n){if(!$a(n))return!1;var t=hr(n);return t==v||"[object DOMException]"==t||"string"==typeof n.message&&"string"==typeof n.name&&!Va(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 Ga(n){return"number"==typeof n||$a(n)&&hr(n)==D}function Va(n){if(!$a(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 Za=rt?Nt(rt):function(n){return $a(n)&&hr(n)==_};var Ha=ut?Nt(ut):function(n){return $a(n)&&ei(n)==m};function Ka(n){return"string"==typeof n||!Ba(n)&&$a(n)&&hr(n)==y}function Ja(n){return"symbol"==typeof n||$a(n)&&hr(n)==b}var Qa=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 Ka(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: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?Ke(eo(n),0,4294967295):0}function uo(n){if("number"==typeof n)return n;if(Ja(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(H,"");var e=an.test(n);return e||cn.test(n)?Gn(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?"":Qr(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(He);var vo=Tr((function(n,t){n=Dn(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,Vu(n),e),r&&(e=Je(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 Do(n,e)}))}(n,t)}));function ko(n,t){if(null==n)return{};var e=dt(Vu(n),(function(n){return[n]}));return t=Ju(t),Ir(n,e,(function(n,e){return t(n,e[0])}))}var Ao=Tu(yo),xo=Tu(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,zt).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 zo=Fu((function(n,t,e){return n+(e?" ":"")+Wo(t)}));var To=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 Tn.test(n)}(n)?function(n){return n.match(Rn)||[]}(n):function(n){return n.match(nn)||[]}(n):n.match(t)||[]}var Uo=Tr((function(n,t){try{return at(n,void 0,t)}catch(e){return Ta(e)?e:new hn(e)}})),Po=qu((function(n,t){return ct(t,(function(t){t=Ci(t),Ze(n,t,ga(n[t],n))})),n}));function $o(n){return function(){return n}}var qo=Au(),Go=Au(!0);function Vo(n){return n}function Zo(n){return wr("function"==typeof n?n:Je(n,1))}var Ho=Tr((function(n,t){return function(e){return _r(e,n,t)}})),Ko=Tr((function(n,t){return function(e){return _r(n,e,t)}}));function Jo(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__=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 Qo(){}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=Da,xe.bind=ga,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=Qr(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),Tr((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?Gr(n,1,t):[]},xe.take=function(n,t,e){return n&&n.length?Gr(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?Gr(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,Ju(t,3),!1,!0):[]},xe.takeWhile=function(n,t){return n&&n.length?tu(n,Ju(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):Ja(n)?[n]:gu(Fi(ao(n)))},xe.toPlainObject=io,xe.transform=function(n,t,e){var r=Ba(n),u=r||Ra(n)||Qa(n);if(t=Ju(t,4),null==e){var i=n&&n.constructor;e=u?r?new i:[]:Pa(n)&&Wa(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 pa(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,Ju(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,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=Hi,xe.words=Mo,xe.wrap=function(n,t){return Ca(au(t),n)},xe.xor=Ki,xe.xorBy=Ji,xe.xorWith=Qi,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,Jo(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),Ke(uo(n),t,e)},xe.clone=function(n){return Je(n,4)},xe.cloneDeep=function(n){return Je(n,5)},xe.cloneDeepWith=function(n,t){return Je(n,5,t="function"==typeof t?t:void 0)},xe.cloneWith=function(n,t){return Je(n,4,t="function"==typeof t?t:void 0)},xe.conformsTo=function(n,t){return null==t||Qe(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=Qr(t);var r=n.length,u=e=void 0===e?r:Ke(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(z,Tt):n},xe.escapeRegExp=function(n){return(n=ao(n))&&Z.test(n)?n.replace(V,"\\$&"):n},xe.every=function(n,t,e){var r=Ba(n)?ft:er;return e&&oi(n,t,e)&&(t=void 0),r(n,Ju(t,3))},xe.find=ua,xe.findIndex=Ni,xe.findKey=function(n,t){return yt(n,Ju(t,3),cr)},xe.findLast=ia,xe.findLastIndex=Bi,xe.findLastKey=function(n,t){return yt(n,Ju(t,3),lr)},xe.floor=lc,xe.forEach=aa,xe.forEachRight=oa,xe.forIn=function(n,t){return null==n?n:ar(n,Ju(t,3),bo)},xe.forInRight=function(n,t){return null==n?n:or(n,Ju(t,3),bo)},xe.forOwn=function(n,t){return n&&cr(n,Ju(t,3))},xe.forOwnRight=function(n,t){return n&&lr(n,Ju(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=Do,xe.head=Si,xe.identity=Vo,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)),Ka(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=Ha,xe.isString=Ka,xe.isSymbol=Ja,xe.isTypedArray=Qa,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=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=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,Vo,dr):void 0},xe.maxBy=function(n,t){return n&&n.length?rr(n,Ju(t,2),dr):void 0},xe.mean=function(n){return Ct(n,Vo)},xe.meanBy=function(n,t){return Ct(n,Ju(t,2))},xe.min=function(n){return n&&n.length?rr(n,Vo,kr):void 0},xe.minBy=function(n,t){return n&&n.length?rr(n,Ju(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 Hn._===this&&(Hn._=On),this},xe.noop=Qo,xe.now=da,xe.pad=function(n,t,e){n=ao(n);var r=(t=eo(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=ao(n);var r=(t=eo(t))?Vt(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)?Dt:xt,u=arguments.length<3;return r(n,Ju(t,4),e,u,nr)},xe.reduceRight=function(n,t,e){var r=Ba(n)?gt:xt,u=arguments.length<3;return r(n,Ju(t,4),e,u,tr)},xe.repeat=function(n,t,e){return t=(e?oi(n,t,e):void 0===t)?1:eo(t),zr(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=Ju(t));++e=i)return n;var o=e-Vt(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=gn(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(Qr(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))&&T.test(n)?n.replace(R,Ht):n},xe.uniqueId=function(n){var t=++kn;return ao(n)+t},xe.upperCase=To,xe.upperFirst=Wo,xe.each=aa,xe.eachRight=oa,xe.first=Si,Jo(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:Ju(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(Vo)},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(wa(Ju(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__=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=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}();Hn._=Kt,void 0===(u=function(){return Kt}.call(t,e,t,r))||(r.exports=u)}).call(this)}).call(this,e(76),e(480)(n))},478:function(n,t,e){"use strict";var r=e(0),u=Object(r.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=u},479:function(n,t,e){"use strict";e.d(t,"a",(function(){return i}));e(77),e(497),e(462),e(78);var r=e(499),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)}))}},480: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}},489:function(n,t,e){var r=e(30),u=e(54),i=e(27),a=e(26),o=e(490);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,D,g=i(t),_=u(g),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 _)&&(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}}},490:function(n,t,e){var r=e(491);n.exports=function(n,t){return new(r(n))(t)}},491:function(n,t,e){var r=e(13),u=e(492),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}},492:function(n,t,e){var r=e(23);n.exports=Array.isArray||function(n){return"Array"==r(n)}},498:function(n,t,e){"use strict";var r=e(0),u=e.n(r),i=e(454),a=e(447),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,")"))}},499:function(n,t,e){var r=e(500);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},500: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}},504:function(n,t,e){"use strict";var r=e(1),u=e(0),i=e.n(u),a=(e(454),e(498)),o=e(447),c=e.n(o),l=e(479),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))})))}},540:function(n,t,e){"use strict";e(29),e(22),e(21),e(52);var r=e(0),u=e.n(r),i=(e(452),e(462),e(454)),a=e(466),o=e.n(a),c=e(504),l=e(479),f=e(460),s=e(467);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),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"installation_guide"==n.category})),A=k?k.value:null,x=g.find((function(n){return"platform"==n.category})),j=x?x.value:null,O=g.find((function(n){return"source"==n.category})),N=O?O.value:null,B=g.find((function(n){return"sink"==n.category})),I=B?B.value:null,S=Object(f.a)().siteConfig.customFields.metadata,L=S.installation,R=S.sources,z=S.sinks,T=S.languages,W=S.frameworks,M=S.technologies,U=S.installation_guides,P=L.platforms,$=j&&P[j],q=N&&R[N],G=I&&z[I],V=b&&T.find((function(n){return n.name===b})),Z=w&&W.find((function(n){return n.name===w})),H=C&&M.find((function(n){return n.name===C})),K=A&&U.find((function(n){return n.name===A})),J=null!==($||q),Q=null!=G,Y=null;Z?Y=r?Z.dark_logo_path:Z.logo_path:H?Y=r?H.dark_logo_path:H.logo_path:K?Y=r?K.dark_logo_path:K.logo_path:V?Y=r?V.dark_logo_path:V.logo_path:$?Y=$.logo_path:q&&(Y=q.logo_path);var X=null;return G&&(X=G.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:D},h&&h+". ",p||D)),u.a.createElement("footer",null,Y&&u.a.createElement(o.a,{src:Y,className:"logo"}),!Y&&J&&u.a.createElement("div",{className:"logo"},u.a.createElement("i",{className:"feather icon-server"})),X&&u.a.createElement(o.a,{src:X,className:"logo"}),!X&&Q&&u.a.createElement("div",{className:"logo"},u.a.createElement("i",{className:"feather icon-server"})),!Y&&!X&&!J&&!Q&&u.a.createElement(c.a,{colorProfile:"guides",tags:d}),u.a.createElement("div",{className:"action"},"read now")))))},h=e(474),d=e(475),p=e.n(d),D=e(447),g=e.n(D);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:g()("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 d9deea5f.838b999e.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[251],{403:function(n,t,e){"use strict";e.r(t);var r=e(0),u=e.n(r),i=e(473),a=e(542),o=e(456);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(o.a,{to:"/guides"},"View All Guides")))),u.a.createElement("main",{className:"container container--s"},u.a.createElement(a.a,{items:e,staggered:null!=e[0].content.metadata.seriesPosition})))}},449: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")},473:function(n,t,e){"use strict";e(483);var r=e(0),u=e.n(r),i=e(484),a=e(472),o=e(1),c=(e(474),e(475),e(485),e(456)),l=e(486),f=e(468),s=e.n(f),v=e(487),h=e.n(v),d=e(462),p=e(449),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(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 a DevOps Automation Platform Helping 200+ Organizations To Ship Faster and Eliminate DevOps Hiring Needs.")),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"})))),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(z,{alt:f.alt,url:v})):u.a.createElement(z,{alt:f.alt,url:v})),u.a.createElement("small",null,a),u.a.createElement("br",null))))},W=e(488),M=e(489),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,D=n.keywords,g=(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}),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)))}},476:function(n,t,e){"use strict";var r=e(9),u=e(0),i=e.n(u),a=e(449),o=e.n(a),c=e(462),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)}}},477: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]",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),H=/^\s+|\s+$/g,K=/^\s+/,J=/\s+$/,Q=/\{(?:\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]",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,Hn=Vn||Zn||Function("return this")(),Kn=t&&!t.nodeType&&t,Jn=Kn&&"object"==typeof r&&r&&!r.nodeType&&r,Qn=Jn&&Jn.exports===Kn,Yn=Qn&&Vn.process,Xn=function(){try{var n=Jn&&Jn.require&&Jn.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 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 Kt=function n(t){var e,r=(t=null==t?Hn:Kt.defaults(Hn.Object(),t,Kt.pick(Hn,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=Hn._,Nn=gn("^"+Fn.call(Cn).replace(V,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Bn=Qn?t.Buffer:void 0,Ln=t.Symbol,zn=t.Uint8Array,$n=Bn?Bn.allocUnsafe:void 0,Vn=Pt(Dn.getPrototypeOf,Dn),Zn=Dn.create,Kn=En.propertyIsEnumerable,Jn=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){}}(),Jt=t.clearTimeout!==Hn.clearTimeout&&t.clearTimeout,Qt=u&&u.now!==Hn.Date.now&&u.now,Yt=t.setTimeout!==Hn.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),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"),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($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 Je(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 gu(n,a)}else{var I=ei(n),S=I==h||I==d;if(Ra(n))return su(n,o);if(I==g||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,Ve(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 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,o)}}i||(i=new ze);var L=i.get(n);if(L)return L;i.set(n,a),Ha(n)?n.forEach((function(r){a.add(Je(r,t,e,r,n,i))})):qa(n)&&n.forEach((function(r,u){a.set(u,Je(r,t,e,u,n,i))}));var R=E?void 0:(v?l?Vu:Gu:l?bo:yo)(n);return ct(R||n,(function(r,u){R&&(r=n[u=r]),$e(a,u,Je(r,t,e,u,n,i))})),a}function Qe(n,t,e){var r=e.length;if(null==n)return!r;for(n=Dn(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=Qu(this,n).delete(n);return this.size-=t?1:0,t},Le.prototype.get=function(n){return Qu(this,n).get(n)},Le.prototype.has=function(n){return Qu(this,n).has(n)},Le.prototype.set=function(n,t){var e=Qu(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(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 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,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&&Jn.call(o,c,1),Jn.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)?Jn.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,Vo),n+"")}function Wr(n){return We(jo(n))}function Mr(n,t){var e=jo(n);return wi(e,Ke(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&&!Ja(a)&&(e?a<=t:a=200){var l=t?null:zu(n);if(l)return qt(l);a=!1,u=It,c=new Re}else c=t?[]:o;n:for(;++r=r?n:Gr(n,t,e)}var fu=Jt||function(n){return Hn.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=Ja(n),a=void 0!==t,o=null===t,c=t==t,l=Ja(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=Dn(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"==Hu(a))var o=new Ne([],!0)}for(r=o?r:e;++r1&&m.reverse(),s&&l<_&&(m.length=l),this&&this!==Hn&&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=Qr(e),r=Qr(r)):(e=Jr(e),r=Jr(r)),u=n(e,r)}return u}}function Nu(n){return qu((function(t){return t=dt(t,Nt(Ju())),Tr((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?" ":Qr(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&&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(Q,"{\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 He(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,Ju(t,3))}function oa(n,t){return(Ba(n)?lt:tr)(n,Ju(t,3))}var ca=mu((function(n,t,e){Cn.call(n,e)?n[e].push(t):Ze(n,e,[t])}));var la=Tr((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,Ju(t,3))}var va=mu((function(n,t,e){n[e?0:1].push(t)}),(function(){return[[],[]]}));var ha=Tr((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=Qt||function(){return Hn.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 Da(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 ga=Tr((function(n,t,e){var r=1;if(e.length){var u=$t(e,Ku(ga));r|=32}return Wu(n,r,t,e,u)})),_a=Tr((function(n,t,e){var r=3;if(e.length){var u=$t(e,Ku(_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(g,t),s?d(n):o}function D(n){var e=n-l;return void 0===l||e>=t||e<0||v&&n-f>=a}function g(){var n=da();if(D(n))return _(n);c=mi(g,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=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)),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=Tr((function(n,t){return Ye(n,1,t)})),ba=Tr((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(Ju())):dt(ir(t,1),Nt(Ju()))).length;return Tr((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")&&!Kn.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,za=tt?Nt(tt):function(n){return $a(n)&&hr(n)==s};function Ta(n){if(!$a(n))return!1;var t=hr(n);return t==v||"[object DOMException]"==t||"string"==typeof n.message&&"string"==typeof n.name&&!Va(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 Ga(n){return"number"==typeof n||$a(n)&&hr(n)==D}function Va(n){if(!$a(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 Za=rt?Nt(rt):function(n){return $a(n)&&hr(n)==_};var Ha=ut?Nt(ut):function(n){return $a(n)&&ei(n)==m};function Ka(n){return"string"==typeof n||!Ba(n)&&$a(n)&&hr(n)==y}function Ja(n){return"symbol"==typeof n||$a(n)&&hr(n)==b}var Qa=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 Ka(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: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?Ke(eo(n),0,4294967295):0}function uo(n){if("number"==typeof n)return n;if(Ja(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(H,"");var e=an.test(n);return e||cn.test(n)?Gn(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?"":Qr(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(He);var vo=Tr((function(n,t){n=Dn(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,Vu(n),e),r&&(e=Je(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 Do(n,e)}))}(n,t)}));function ko(n,t){if(null==n)return{};var e=dt(Vu(n),(function(n){return[n]}));return t=Ju(t),Ir(n,e,(function(n,e){return t(n,e[0])}))}var Ao=Tu(yo),xo=Tu(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,zt).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 zo=Fu((function(n,t,e){return n+(e?" ":"")+Wo(t)}));var To=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 Tn.test(n)}(n)?function(n){return n.match(Rn)||[]}(n):function(n){return n.match(nn)||[]}(n):n.match(t)||[]}var Uo=Tr((function(n,t){try{return at(n,void 0,t)}catch(e){return Ta(e)?e:new hn(e)}})),Po=qu((function(n,t){return ct(t,(function(t){t=Ci(t),Ze(n,t,ga(n[t],n))})),n}));function $o(n){return function(){return n}}var qo=Au(),Go=Au(!0);function Vo(n){return n}function Zo(n){return wr("function"==typeof n?n:Je(n,1))}var Ho=Tr((function(n,t){return function(e){return _r(e,n,t)}})),Ko=Tr((function(n,t){return function(e){return _r(n,e,t)}}));function Jo(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__=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 Qo(){}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=Da,xe.bind=ga,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=Qr(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),Tr((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?Gr(n,1,t):[]},xe.take=function(n,t,e){return n&&n.length?Gr(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?Gr(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,Ju(t,3),!1,!0):[]},xe.takeWhile=function(n,t){return n&&n.length?tu(n,Ju(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):Ja(n)?[n]:gu(Fi(ao(n)))},xe.toPlainObject=io,xe.transform=function(n,t,e){var r=Ba(n),u=r||Ra(n)||Qa(n);if(t=Ju(t,4),null==e){var i=n&&n.constructor;e=u?r?new i:[]:Pa(n)&&Wa(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 pa(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,Ju(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,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=Hi,xe.words=Mo,xe.wrap=function(n,t){return Ca(au(t),n)},xe.xor=Ki,xe.xorBy=Ji,xe.xorWith=Qi,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,Jo(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),Ke(uo(n),t,e)},xe.clone=function(n){return Je(n,4)},xe.cloneDeep=function(n){return Je(n,5)},xe.cloneDeepWith=function(n,t){return Je(n,5,t="function"==typeof t?t:void 0)},xe.cloneWith=function(n,t){return Je(n,4,t="function"==typeof t?t:void 0)},xe.conformsTo=function(n,t){return null==t||Qe(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=Qr(t);var r=n.length,u=e=void 0===e?r:Ke(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(z,Tt):n},xe.escapeRegExp=function(n){return(n=ao(n))&&Z.test(n)?n.replace(V,"\\$&"):n},xe.every=function(n,t,e){var r=Ba(n)?ft:er;return e&&oi(n,t,e)&&(t=void 0),r(n,Ju(t,3))},xe.find=ua,xe.findIndex=Ni,xe.findKey=function(n,t){return yt(n,Ju(t,3),cr)},xe.findLast=ia,xe.findLastIndex=Bi,xe.findLastKey=function(n,t){return yt(n,Ju(t,3),lr)},xe.floor=lc,xe.forEach=aa,xe.forEachRight=oa,xe.forIn=function(n,t){return null==n?n:ar(n,Ju(t,3),bo)},xe.forInRight=function(n,t){return null==n?n:or(n,Ju(t,3),bo)},xe.forOwn=function(n,t){return n&&cr(n,Ju(t,3))},xe.forOwnRight=function(n,t){return n&&lr(n,Ju(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=Do,xe.head=Si,xe.identity=Vo,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)),Ka(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=Ha,xe.isString=Ka,xe.isSymbol=Ja,xe.isTypedArray=Qa,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=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=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,Vo,dr):void 0},xe.maxBy=function(n,t){return n&&n.length?rr(n,Ju(t,2),dr):void 0},xe.mean=function(n){return Ct(n,Vo)},xe.meanBy=function(n,t){return Ct(n,Ju(t,2))},xe.min=function(n){return n&&n.length?rr(n,Vo,kr):void 0},xe.minBy=function(n,t){return n&&n.length?rr(n,Ju(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 Hn._===this&&(Hn._=On),this},xe.noop=Qo,xe.now=da,xe.pad=function(n,t,e){n=ao(n);var r=(t=eo(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=ao(n);var r=(t=eo(t))?Vt(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)?Dt:xt,u=arguments.length<3;return r(n,Ju(t,4),e,u,nr)},xe.reduceRight=function(n,t,e){var r=Ba(n)?gt:xt,u=arguments.length<3;return r(n,Ju(t,4),e,u,tr)},xe.repeat=function(n,t,e){return t=(e?oi(n,t,e):void 0===t)?1:eo(t),zr(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=Ju(t));++e=i)return n;var o=e-Vt(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=gn(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(Qr(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))&&T.test(n)?n.replace(R,Ht):n},xe.uniqueId=function(n){var t=++kn;return ao(n)+t},xe.upperCase=To,xe.upperFirst=Wo,xe.each=aa,xe.eachRight=oa,xe.first=Si,Jo(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:Ju(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(Vo)},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(wa(Ju(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__=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=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}();Hn._=Kt,void 0===(u=function(){return Kt}.call(t,e,t,r))||(r.exports=u)}).call(this)}).call(this,e(76),e(482)(n))},480:function(n,t,e){"use strict";var r=e(0),u=Object(r.createContext)({tabGroupChoices:{},setTabGroupChoices:function(){}});t.a=u},481:function(n,t,e){"use strict";e.d(t,"a",(function(){return i}));e(77),e(499),e(464),e(78);var r=e(501),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)}))}},482: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}},491:function(n,t,e){var r=e(30),u=e(54),i=e(27),a=e(26),o=e(492);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,D,g=i(t),_=u(g),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 _)&&(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}}},492:function(n,t,e){var r=e(493);n.exports=function(n,t){return new(r(n))(t)}},493:function(n,t,e){var r=e(13),u=e(494),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}},494:function(n,t,e){var r=e(23);n.exports=Array.isArray||function(n){return"Array"==r(n)}},500:function(n,t,e){"use strict";var r=e(0),u=e.n(r),i=e(456),a=e(449),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,")"))}},501:function(n,t,e){var r=e(502);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},502: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}},506:function(n,t,e){"use strict";var r=e(1),u=e(0),i=e.n(u),a=(e(456),e(500)),o=e(449),c=e.n(o),l=e(481),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))})))}},542:function(n,t,e){"use strict";e(29),e(22),e(21),e(52);var r=e(0),u=e.n(r),i=(e(454),e(464),e(456)),a=e(468),o=e.n(a),c=e(506),l=e(481),f=e(462),s=e(469);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),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"installation_guide"==n.category})),A=k?k.value:null,x=g.find((function(n){return"platform"==n.category})),j=x?x.value:null,O=g.find((function(n){return"source"==n.category})),N=O?O.value:null,B=g.find((function(n){return"sink"==n.category})),I=B?B.value:null,S=Object(f.a)().siteConfig.customFields.metadata,L=S.installation,R=S.sources,z=S.sinks,T=S.languages,W=S.frameworks,M=S.technologies,U=S.installation_guides,P=L.platforms,$=j&&P[j],q=N&&R[N],G=I&&z[I],V=b&&T.find((function(n){return n.name===b})),Z=w&&W.find((function(n){return n.name===w})),H=C&&M.find((function(n){return n.name===C})),K=A&&U.find((function(n){return n.name===A})),J=null!==($||q),Q=null!=G,Y=null;Z?Y=r?Z.dark_logo_path:Z.logo_path:H?Y=r?H.dark_logo_path:H.logo_path:K?Y=r?K.dark_logo_path:K.logo_path:V?Y=r?V.dark_logo_path:V.logo_path:$?Y=$.logo_path:q&&(Y=q.logo_path);var X=null;return G&&(X=G.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:D},h&&h+". ",p||D)),u.a.createElement("footer",null,Y&&u.a.createElement(o.a,{src:Y,className:"logo"}),!Y&&J&&u.a.createElement("div",{className:"logo"},u.a.createElement("i",{className:"feather icon-server"})),X&&u.a.createElement(o.a,{src:X,className:"logo"}),!X&&Q&&u.a.createElement("div",{className:"logo"},u.a.createElement("i",{className:"feather icon-server"})),!Y&&!X&&!J&&!Q&&u.a.createElement(c.a,{colorProfile:"guides",tags:d}),u.a.createElement("div",{className:"action"},"read now")))))},h=e(476),d=e(477),p=e.n(d),D=e(449),g=e.n(D);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:g()("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/d9deea5f.54f0dc79.js.LICENSE.txt b/d9deea5f.838b999e.js.LICENSE.txt similarity index 100% rename from d9deea5f.54f0dc79.js.LICENSE.txt rename to d9deea5f.838b999e.js.LICENSE.txt diff --git a/a8a9c166.84ed9ceb.js b/da253275.70bfb721.js similarity index 87% rename from a8a9c166.84ed9ceb.js rename to da253275.70bfb721.js index 22fa71e5f1..272ae587f1 100644 --- a/a8a9c166.84ed9ceb.js +++ b/da253275.70bfb721.js @@ -1,2 +1,2 @@ -/*! For license information please see a8a9c166.84ed9ceb.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[184],{336: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(449)),i=(n(456),n(453),n(448)),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(447),n(455)),i=n.n(a);n(133);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"),"."))}},459: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.70bfb721.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[252],{404: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(451)),i=(n(458),n(455),n(450)),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(449),n(457)),i=n.n(a);n(133);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"),"."))}},461: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.e41848ab.js.LICENSE.txt b/da253275.70bfb721.js.LICENSE.txt similarity index 100% rename from db96bb7d.e41848ab.js.LICENSE.txt rename to da253275.70bfb721.js.LICENSE.txt diff --git a/dab3a2be.412b34db.js b/dab3a2be.f332705d.js similarity index 91% rename from dab3a2be.412b34db.js rename to dab3a2be.f332705d.js index 79d7b486fa..0c6f05a3bb 100644 --- a/dab3a2be.412b34db.js +++ b/dab3a2be.f332705d.js @@ -1,2 +1,2 @@ -/*! For license information please see dab3a2be.412b34db.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[251],{403: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(449)),i=t(448),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},447: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.f332705d.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[253],{405: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(451)),i=t(450),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},449: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.0889cadf.js.LICENSE.txt b/dab3a2be.f332705d.js.LICENSE.txt similarity index 100% rename from dc00a797.0889cadf.js.LICENSE.txt rename to dab3a2be.f332705d.js.LICENSE.txt diff --git a/db372ba8.b6fffcc9.js b/db372ba8.32fe05b2.js similarity index 96% rename from db372ba8.b6fffcc9.js rename to db372ba8.32fe05b2.js index d4b7453122..c346120de8 100644 --- a/db372ba8.b6fffcc9.js +++ b/db372ba8.32fe05b2.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[252],{404: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(449)),i=a(456),s=a(461),o=a(464),c=a(448),b=a(453),u=a(457),p={last_modified_on:"2024-05-03",$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:"13 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://console.qovery.com/"},Object(r.b)("img",{src:"/img/Qovery_Sign_Up_Page.png",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 a headless (without GUI) environment, you can use the following command to sign up and sign in:"),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 Qovery sign-up page will open. Follow the instructions to sign up and sign 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},448:function(e,t,a){"use strict";a(450);var n=a(0),l=a.n(n),r=a(447),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)}},452: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""}}})},453:function(e,t,a){"use strict";a(452);var n=a(0),l=a.n(n),r=a(448);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)}},454:function(e,t,a){"use strict";var n=a(1),l=a(0),r=a.n(l),i=a(39),s=a(458),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}))}},456:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=(a(447),a(455)),i=a.n(r);a(133);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"),"."))}},457:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=a(454),i=a(447),s=a.n(i);a(134);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)}},458:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},461:function(e,t,a){"use strict";var n=a(1),l=(a(465),a(462),a(52),a(29),a(22),a(21),a(0)),r=a.n(l),i=a(469),s=a(447),o=a.n(s),c=a(455),b=a.n(c),u=a(468),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])}},464: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([[254],{406: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(451)),i=a(458),s=a(463),o=a(466),c=a(450),b=a(455),u=a(459),p={last_modified_on:"2024-05-03",$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:"13 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://console.qovery.com/"},Object(r.b)("img",{src:"/img/Qovery_Sign_Up_Page.png",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 a headless (without GUI) environment, you can use the following command to sign up and sign in:"),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 Qovery sign-up page will open. Follow the instructions to sign up and sign 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},450:function(e,t,a){"use strict";a(452);var n=a(0),l=a.n(n),r=a(449),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)}},454: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""}}})},455:function(e,t,a){"use strict";a(454);var n=a(0),l=a.n(n),r=a(450);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)}},456:function(e,t,a){"use strict";var n=a(1),l=a(0),r=a.n(l),i=a(39),s=a(460),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}))}},458:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=(a(449),a(457)),i=a.n(r);a(133);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"),"."))}},459:function(e,t,a){"use strict";var n=a(0),l=a.n(n),r=a(456),i=a(449),s=a.n(i);a(134);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)}},460:function(e,t,a){"use strict";function n(e){return!1===/^(https?:|\/\/)/.test(e)}a.d(t,"a",(function(){return n}))},463:function(e,t,a){"use strict";var n=a(1),l=(a(467),a(464),a(52),a(29),a(22),a(21),a(0)),r=a.n(l),i=a(471),s=a(449),o=a.n(s),c=a(457),b=a.n(c),u=a(470),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])}},466: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.e41848ab.js b/db96bb7d.8c62b3ef.js similarity index 95% rename from db96bb7d.e41848ab.js rename to db96bb7d.8c62b3ef.js index f1d239542b..a3698fa8c4 100644 --- a/db96bb7d.e41848ab.js +++ b/db96bb7d.8c62b3ef.js @@ -1,2 +1,2 @@ -/*! For license information please see db96bb7d.e41848ab.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[253],{405: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(449)),i=n(448),l=n(456),c={last_modified_on:"2023-12-10",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-deprecated"},"Mode (Deprecated)"),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"We are re-building this feature and thus you will always have to select a mode when creating a new environment")),Object(a.b)("p",null,"You can automatically assign a ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"docs.using-qovery.configuration.environment#type-of-environment"}),"type of environments")," based on his name."),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)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"We are re-building this feature and thus you will always have to select a clsuter when manually creating a new environment. This feature still works for preview environments.")),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},447: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}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(447),n(455)),i=n.n(a);n(133);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"),"."))}},459: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.8c62b3ef.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[255],{407: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(451)),i=n(450),l=n(458),c={last_modified_on:"2023-12-10",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-deprecated"},"Mode (Deprecated)"),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"We are re-building this feature and thus you will always have to select a mode when creating a new environment")),Object(a.b)("p",null,"You can automatically assign a ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"docs.using-qovery.configuration.environment#type-of-environment"}),"type of environments")," based on his name."),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)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"We are re-building this feature and thus you will always have to select a clsuter when manually creating a new environment. This feature still works for preview environments.")),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},449: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}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(449),n(457)),i=n.n(a);n(133);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"),"."))}},461: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.01fb1818.js.LICENSE.txt b/db96bb7d.8c62b3ef.js.LICENSE.txt similarity index 100% rename from de0a75d9.01fb1818.js.LICENSE.txt rename to db96bb7d.8c62b3ef.js.LICENSE.txt diff --git a/dbe0f891.673f930d.js b/dbe0f891.75f6727e.js similarity index 73% rename from dbe0f891.673f930d.js rename to dbe0f891.75f6727e.js index 3ae865662c..e7c7be7c5a 100644 --- a/dbe0f891.673f930d.js +++ b/dbe0f891.75f6727e.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[254],{406: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([[256],{408: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.0889cadf.js b/dc00a797.d833e255.js similarity index 98% rename from dc00a797.0889cadf.js rename to dc00a797.d833e255.js index 9f0502aa55..c444cef6f0 100644 --- a/dc00a797.0889cadf.js +++ b/dc00a797.d833e255.js @@ -1,2 +1,2 @@ -/*! For license information please see dc00a797.0889cadf.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[255],{407: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(449)),l=n(456),c=(n(457),n(448)),i=(n(453),{last_modified_on:"2024-07-30",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:"Labels & Annotations",permalink:"/docs/using-qovery/configuration/organization/labels-annotations"},next:{title:"Cluster Advanced Settings",permalink:"/docs/using-qovery/configuration/cluster-advanced-settings"}},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:"/docs/getting-started/install-qovery/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/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/#attach-aws-credentials"}),"here for AWS"),", ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/#attach-scaleway-credentials"}),"here for Scaleway"),", ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/#attach-gcp-credentials"}),"here for GCP"),".")),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/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/#attach-aws-credentials"}),"Procedure for AWS account"),", ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/#attach-scaleway-credentials"}),"Procedure for Scaleway account"),", ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/#attach-gcp-credentials"}),"Procedure for GCP 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"},"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"},"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"},"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,"For AWS EKS clusters, you have the possibility to enable ",Object(o.b)("inlineCode",{parentName:"p"},"Karpenter")," autoscaler to improve the efficiency and cost of running workloads on your cluster. You can check the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://karpenter.sh/docs/"}),"official documentation")," for more information."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/karpenter.png",alt:"Enable Karpenter"})),Object(o.b)("p",null,"Today, only new non-production clusters are supported. It means you won't be able to enable it on your already existing cluster. It will be supported soon."),Object(o.b)("p",null,"By activating Karpenter, you have to set:"),Object(o.b)("ul",null,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..)."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Default node architecture"),": If you build your application with the Qovery CI, your application will be built using this architecture by default."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Spot instances"),": In order to reduce even more your costs, you can also enable the spot instances on your clusters. Spot instances cost up to 90% less compared to On-Demand prices. But keep in mind that spot instances can be terminated by the cloud provider at any time. Check this ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://aws.amazon.com/ec2/spot/"}),"documentation")," for more information. Even if this flag is enabled, the statefulsets won't run on spot instances.")),Object(o.b)("br",null),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"A SQS queue will be created. Before deploying your cluster, update the IAM permissions of the Qovery user, make sure to use the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://hub.qovery.com/files/qovery-iam-aws.json"}),"latest version here")," to add the permission on SQS.")),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/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/#attach-aws-credentials"}),"Procedure for AWS account"),", ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/#attach-scaleway-credentials"}),"Procedure for Scaleway account"),", ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/#attach-gcp-credentials"}),"Procedure for GCP 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 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"),", ",Object(o.b)("inlineCode",{parentName:"td"},"Scaleway Secret Key"),", ",Object(o.b)("inlineCode",{parentName:"td"},"Scaleway Project ID")," and ",Object(o.b)("inlineCode",{parentName:"td"},"Scaleway Organization ID"))),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"GCP"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("inlineCode",{parentName:"td"},"GCP JSON key"))))),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:"image-registry"},"Image registry"),Object(o.b)("p",null,"In this tab, you will see that a container registry already exist (called ",Object(o.b)("inlineCode",{parentName:"p"},"registry-{$UIID}"),").\nThis is your cloud provider container registry used by Qovery to manage the deployment of your applications by mirroring the docker images."),Object(o.b)("p",null,"The credentials configured on this registry are the one used to create the cluster. But you can still update them if you prefer to manage them separately (dedicated pair of creds just to access the registry)."),Object(o.b)("p",null,"Check ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/image-mirroring/"}),"this link")," for more information."),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"),", ",Object(o.b)("strong",{parentName:"p"},"Custom VPC subnet"),", ",Object(o.b)("strong",{parentName:"p"},"Deploy on existing VPC")," 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 GCP with a VPC managed by Qovery 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 ",Object(o.b)("inlineCode",{parentName:"p"},"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,"Here is what will be deployed on ",Object(o.b)("inlineCode",{parentName:"p"},"GCP"),":"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Cloud Nats"),Object(o.b)("li",{parentName:"ul"},"Static IPs"),Object(o.b)("li",{parentName:"ul"},"Routers")),Object(o.b)("p",null,"Once set up, here is the procedure to find your static IP addresses on ",Object(o.b)("inlineCode",{parentName:"p"},"AWS"),":"),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)("p",null,"Once set up, here is the procedure to find your static IP addresses on ",Object(o.b)("inlineCode",{parentName:"p"},"GCP"),":"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"On your GCP account, select the IP addresses service."),Object(o.b)("li",{parentName:"ul"},"In the list you will find your static IP used by your cluster router.")),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)("p",null,"This feature has been activated by default. Since February 1, 2024, AWS charge public IPv4 Addresses. Disabling it may cost you more, depending on the number of nodes in your cluster. Check this ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://aws.amazon.com/blogs/aws/new-aws-public-ipv4-address-charge-public-ip-insights/"}),"link")," for more information.")),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 with a VPC managed by Qovery 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)("h5",{id:"use-existing-vpc"},"Use existing VPC"),Object(o.b)("p",null,"The ",Object(o.b)("strong",{parentName:"p"},"Deploy on existing VPC")," feature is currently only available to clusters deployed on ",Object(o.b)("inlineCode",{parentName:"p"},"AWS")," and ",Object(o.b)("inlineCode",{parentName:"p"},"GCP")," when you select ",Object(o.b)("inlineCode",{parentName:"p"},"Deploy on my existing VPC")," VPC mode and can only be enabled at cluster creation."),Object(o.b)("h5",{id:"use-existing-vpc---aws"},"Use existing VPC - AWS:"),Object(o.b)("p",null,"You have to specify the ",Object(o.b)("inlineCode",{parentName:"p"},"VPC id")," (1) and ensure that in your VPC settings you have enabled the ",Object(o.b)("inlineCode",{parentName:"p"},"DNS hostnames")," (2):"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/existing_vpc_aws_dns_hostnames.png",alt:"Existing VPC AWS DNS Hostnmaes"})),Object(o.b)("p",null,"Then you have to specify the different subnets ids:"),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"EKS"),":"),Object(o.b)("p",null,"The EKS subnets are mandatory, you have to specify at least ",Object(o.b)("strong",{parentName:"p"},"one subnet id per zone")," (1) and ensure you have enabled the ",Object(o.b)("strong",{parentName:"p"},"auto-assign public IPv4 address")," setting on your subnets (2)."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/existing_vpc_aws_auto_assign.png",alt:"Existing VPC AWS DNS Hostnmaes"})),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you have activated ",Object(o.b)("inlineCode",{parentName:"p"},"Karpenter"),", you will have to specify at least ",Object(o.b)("strong",{parentName:"p"},"one subnet id per zone"),". These subnets have to be private and connected to internet through a NAT Gateway. They will be used for AWS Fargate profile.")),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Managed databases"),":"),Object(o.b)("p",null,"This section is exclusively for enabling managed databases (container databases will be enabled by default)."),Object(o.b)("p",null,"Depending on the managed databases you want to you use (",Object(o.b)("strong",{parentName:"p"},"MongoDB"),", ",Object(o.b)("strong",{parentName:"p"},"RDS:MySQL/PostgreSQL")," and ",Object(o.b)("strong",{parentName:"p"},"Redis"),"), specify at least one subnet id per zone."),Object(o.b)("h5",{id:"use-existing-vpc---gcp"},"Use existing VPC - GCP:"),Object(o.b)("p",null,"In GCP you have two VPC modes: ",Object(o.b)("inlineCode",{parentName:"p"},"Automatic")," or ",Object(o.b)("inlineCode",{parentName:"p"},"Custom"),"."),Object(o.b)("p",null,"If you are using an automatic or a custom VPC, you have to set:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Your VPC Name"),Object(o.b)("li",{parentName:"ul"},"External project id (optional): by default, the project id used is the one specified in the credentials file. But if your VPC is defined in another GCP project, you have to specify the Project id.")),Object(o.b)("p",null,"In addition if you are using a custom VPC, you have to set:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Your Subnet range name (",Object(o.b)("inlineCode",{parentName:"li"},"https://console.cloud.google.com/networking/networks/details/?project=&pageTab=SUBNETS"),")")),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"You can also specify (optional):"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Pod ipv4 address range name"),Object(o.b)("li",{parentName:"ul"},"Additional cluster pod ipv4 ranges names (separated with a comma)"),Object(o.b)("li",{parentName:"ul"},"Ipv4 service range name")),Object(o.b)("p",null,"For these ranges, you have to create Secondary IPv4 ranges inside your subnet.")),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Please keep in mind that enabling them later may not be possible.")),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 ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"#cleaning-up-a-cluster-from-your-aws-account"}),"this section")," 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 ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"#cleaning-up-a-cluster-from-your-aws-account"}),"this section")," 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 ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"#cleaning-up-a-cluster-from-your-aws-account"}),"this section")," 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)("h4",{id:"audit-logs"},"Audit logs"),Object(o.b)("p",null,"To get the cluster filtered audit logs, open the ",Object(o.b)("inlineCode",{parentName:"p"},"...")," section and press ",Object(o.b)("inlineCode",{parentName:"p"},"See audit logs"),"."),Object(o.b)("p",null,"You will be redirected to the audit logs section. A filter on the dedicated cluster will be applied. You only see the audit logs regarding cluster operations."),Object(o.b)("h4",{id:"get-your-cluster-id"},"Get your cluster id"),Object(o.b)("p",null,"To get your Qovery cluster id, open the ",Object(o.b)("inlineCode",{parentName:"p"},"...")," section and press ",Object(o.b)("inlineCode",{parentName:"p"},"Copy identifier"),"."),Object(o.b)("p",null,"The cluster id in Qovery will be in your clipboard."),Object(o.b)("h4",{id:"get-your-cluster-kubeconfig-file"},"Get your cluster kubeconfig file"),Object(o.b)("p",null,"If you need to get your kubeconfig file, open the ",Object(o.b)("inlineCode",{parentName:"p"},"...")," section and press ",Object(o.b)("inlineCode",{parentName:"p"},"Get Kubeconfig"),"."),Object(o.b)("p",null,"Then the kubeconfig yaml file will be automatically downloaded."),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"))),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),l=n(39),c=n(458),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}))}},455:function(e,t,n){"use strict";var a=n(459),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("&"):""}},456:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(447),n(455)),l=n.n(o);n(133);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"),"."))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(454),l=n(447),c=n.n(l);n(134);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)}},458:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},459: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.d833e255.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 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(451)),l=n(458),c=(n(459),n(450)),i=(n(455),{last_modified_on:"2024-07-30",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:"Labels & Annotations",permalink:"/docs/using-qovery/configuration/organization/labels-annotations"},next:{title:"Cluster Advanced Settings",permalink:"/docs/using-qovery/configuration/cluster-advanced-settings"}},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:"/docs/getting-started/install-qovery/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/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/#attach-aws-credentials"}),"here for AWS"),", ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/#attach-scaleway-credentials"}),"here for Scaleway"),", ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/#attach-gcp-credentials"}),"here for GCP"),".")),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/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/#attach-aws-credentials"}),"Procedure for AWS account"),", ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/#attach-scaleway-credentials"}),"Procedure for Scaleway account"),", ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/#attach-gcp-credentials"}),"Procedure for GCP 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"},"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"},"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"},"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,"For AWS EKS clusters, you have the possibility to enable ",Object(o.b)("inlineCode",{parentName:"p"},"Karpenter")," autoscaler to improve the efficiency and cost of running workloads on your cluster. You can check the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://karpenter.sh/docs/"}),"official documentation")," for more information."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/karpenter.png",alt:"Enable Karpenter"})),Object(o.b)("p",null,"Today, only new non-production clusters are supported. It means you won't be able to enable it on your already existing cluster. It will be supported soon."),Object(o.b)("p",null,"By activating Karpenter, you have to set:"),Object(o.b)("ul",null,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..)."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Default node architecture"),": If you build your application with the Qovery CI, your application will be built using this architecture by default."),Object(o.b)("li",{parentName:"ul"},Object(o.b)("inlineCode",{parentName:"li"},"Spot instances"),": In order to reduce even more your costs, you can also enable the spot instances on your clusters. Spot instances cost up to 90% less compared to On-Demand prices. But keep in mind that spot instances can be terminated by the cloud provider at any time. Check this ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://aws.amazon.com/ec2/spot/"}),"documentation")," for more information. Even if this flag is enabled, the statefulsets won't run on spot instances.")),Object(o.b)("br",null),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"A SQS queue will be created. Before deploying your cluster, update the IAM permissions of the Qovery user, make sure to use the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://hub.qovery.com/files/qovery-iam-aws.json"}),"latest version here")," to add the permission on SQS.")),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/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/#attach-aws-credentials"}),"Procedure for AWS account"),", ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/#attach-scaleway-credentials"}),"Procedure for Scaleway account"),", ",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/#attach-gcp-credentials"}),"Procedure for GCP 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 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"),", ",Object(o.b)("inlineCode",{parentName:"td"},"Scaleway Secret Key"),", ",Object(o.b)("inlineCode",{parentName:"td"},"Scaleway Project ID")," and ",Object(o.b)("inlineCode",{parentName:"td"},"Scaleway Organization ID"))),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"GCP"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("inlineCode",{parentName:"td"},"GCP JSON key"))))),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:"image-registry"},"Image registry"),Object(o.b)("p",null,"In this tab, you will see that a container registry already exist (called ",Object(o.b)("inlineCode",{parentName:"p"},"registry-{$UIID}"),").\nThis is your cloud provider container registry used by Qovery to manage the deployment of your applications by mirroring the docker images."),Object(o.b)("p",null,"The credentials configured on this registry are the one used to create the cluster. But you can still update them if you prefer to manage them separately (dedicated pair of creds just to access the registry)."),Object(o.b)("p",null,"Check ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/image-mirroring/"}),"this link")," for more information."),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"),", ",Object(o.b)("strong",{parentName:"p"},"Custom VPC subnet"),", ",Object(o.b)("strong",{parentName:"p"},"Deploy on existing VPC")," 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 GCP with a VPC managed by Qovery 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 ",Object(o.b)("inlineCode",{parentName:"p"},"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,"Here is what will be deployed on ",Object(o.b)("inlineCode",{parentName:"p"},"GCP"),":"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Cloud Nats"),Object(o.b)("li",{parentName:"ul"},"Static IPs"),Object(o.b)("li",{parentName:"ul"},"Routers")),Object(o.b)("p",null,"Once set up, here is the procedure to find your static IP addresses on ",Object(o.b)("inlineCode",{parentName:"p"},"AWS"),":"),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)("p",null,"Once set up, here is the procedure to find your static IP addresses on ",Object(o.b)("inlineCode",{parentName:"p"},"GCP"),":"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"On your GCP account, select the IP addresses service."),Object(o.b)("li",{parentName:"ul"},"In the list you will find your static IP used by your cluster router.")),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)("p",null,"This feature has been activated by default. Since February 1, 2024, AWS charge public IPv4 Addresses. Disabling it may cost you more, depending on the number of nodes in your cluster. Check this ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://aws.amazon.com/blogs/aws/new-aws-public-ipv4-address-charge-public-ip-insights/"}),"link")," for more information.")),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 with a VPC managed by Qovery 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)("h5",{id:"use-existing-vpc"},"Use existing VPC"),Object(o.b)("p",null,"The ",Object(o.b)("strong",{parentName:"p"},"Deploy on existing VPC")," feature is currently only available to clusters deployed on ",Object(o.b)("inlineCode",{parentName:"p"},"AWS")," and ",Object(o.b)("inlineCode",{parentName:"p"},"GCP")," when you select ",Object(o.b)("inlineCode",{parentName:"p"},"Deploy on my existing VPC")," VPC mode and can only be enabled at cluster creation."),Object(o.b)("h5",{id:"use-existing-vpc---aws"},"Use existing VPC - AWS:"),Object(o.b)("p",null,"You have to specify the ",Object(o.b)("inlineCode",{parentName:"p"},"VPC id")," (1) and ensure that in your VPC settings you have enabled the ",Object(o.b)("inlineCode",{parentName:"p"},"DNS hostnames")," (2):"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/existing_vpc_aws_dns_hostnames.png",alt:"Existing VPC AWS DNS Hostnmaes"})),Object(o.b)("p",null,"Then you have to specify the different subnets ids:"),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"EKS"),":"),Object(o.b)("p",null,"The EKS subnets are mandatory, you have to specify at least ",Object(o.b)("strong",{parentName:"p"},"one subnet id per zone")," (1) and ensure you have enabled the ",Object(o.b)("strong",{parentName:"p"},"auto-assign public IPv4 address")," setting on your subnets (2)."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/configuration/clusters/existing_vpc_aws_auto_assign.png",alt:"Existing VPC AWS DNS Hostnmaes"})),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If you have activated ",Object(o.b)("inlineCode",{parentName:"p"},"Karpenter"),", you will have to specify at least ",Object(o.b)("strong",{parentName:"p"},"one subnet id per zone"),". These subnets have to be private and connected to internet through a NAT Gateway. They will be used for AWS Fargate profile.")),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Managed databases"),":"),Object(o.b)("p",null,"This section is exclusively for enabling managed databases (container databases will be enabled by default)."),Object(o.b)("p",null,"Depending on the managed databases you want to you use (",Object(o.b)("strong",{parentName:"p"},"MongoDB"),", ",Object(o.b)("strong",{parentName:"p"},"RDS:MySQL/PostgreSQL")," and ",Object(o.b)("strong",{parentName:"p"},"Redis"),"), specify at least one subnet id per zone."),Object(o.b)("h5",{id:"use-existing-vpc---gcp"},"Use existing VPC - GCP:"),Object(o.b)("p",null,"In GCP you have two VPC modes: ",Object(o.b)("inlineCode",{parentName:"p"},"Automatic")," or ",Object(o.b)("inlineCode",{parentName:"p"},"Custom"),"."),Object(o.b)("p",null,"If you are using an automatic or a custom VPC, you have to set:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Your VPC Name"),Object(o.b)("li",{parentName:"ul"},"External project id (optional): by default, the project id used is the one specified in the credentials file. But if your VPC is defined in another GCP project, you have to specify the Project id.")),Object(o.b)("p",null,"In addition if you are using a custom VPC, you have to set:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Your Subnet range name (",Object(o.b)("inlineCode",{parentName:"li"},"https://console.cloud.google.com/networking/networks/details/?project=&pageTab=SUBNETS"),")")),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"You can also specify (optional):"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Pod ipv4 address range name"),Object(o.b)("li",{parentName:"ul"},"Additional cluster pod ipv4 ranges names (separated with a comma)"),Object(o.b)("li",{parentName:"ul"},"Ipv4 service range name")),Object(o.b)("p",null,"For these ranges, you have to create Secondary IPv4 ranges inside your subnet.")),Object(o.b)(c.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Please keep in mind that enabling them later may not be possible.")),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 ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"#cleaning-up-a-cluster-from-your-aws-account"}),"this section")," 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 ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"#cleaning-up-a-cluster-from-your-aws-account"}),"this section")," 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 ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"#cleaning-up-a-cluster-from-your-aws-account"}),"this section")," 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)("h4",{id:"audit-logs"},"Audit logs"),Object(o.b)("p",null,"To get the cluster filtered audit logs, open the ",Object(o.b)("inlineCode",{parentName:"p"},"...")," section and press ",Object(o.b)("inlineCode",{parentName:"p"},"See audit logs"),"."),Object(o.b)("p",null,"You will be redirected to the audit logs section. A filter on the dedicated cluster will be applied. You only see the audit logs regarding cluster operations."),Object(o.b)("h4",{id:"get-your-cluster-id"},"Get your cluster id"),Object(o.b)("p",null,"To get your Qovery cluster id, open the ",Object(o.b)("inlineCode",{parentName:"p"},"...")," section and press ",Object(o.b)("inlineCode",{parentName:"p"},"Copy identifier"),"."),Object(o.b)("p",null,"The cluster id in Qovery will be in your clipboard."),Object(o.b)("h4",{id:"get-your-cluster-kubeconfig-file"},"Get your cluster kubeconfig file"),Object(o.b)("p",null,"If you need to get your kubeconfig file, open the ",Object(o.b)("inlineCode",{parentName:"p"},"...")," section and press ",Object(o.b)("inlineCode",{parentName:"p"},"Get Kubeconfig"),"."),Object(o.b)("p",null,"Then the kubeconfig yaml file will be automatically downloaded."),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"))),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),l=n(39),c=n(460),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}))}},457:function(e,t,n){"use strict";var a=n(461),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("&"):""}},458:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(449),n(457)),l=n.n(o);n(133);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"),"."))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(456),l=n(449),c=n.n(l);n(134);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)}},460:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},461: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.dc8cfedf.js.LICENSE.txt b/dc00a797.d833e255.js.LICENSE.txt similarity index 100% rename from dea3d534.dc8cfedf.js.LICENSE.txt rename to dc00a797.d833e255.js.LICENSE.txt diff --git a/7aa59ca3.8f5ea392.js b/de0a75d9.8e7073f0.js similarity index 92% rename from 7aa59ca3.8f5ea392.js rename to de0a75d9.8e7073f0.js index 71268d71a8..51c3868c5f 100644 --- a/7aa59ca3.8f5ea392.js +++ b/de0a75d9.8e7073f0.js @@ -1,2 +1,2 @@ -/*! For license information please see 7aa59ca3.8f5ea392.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[135],{286: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(449)),c=n(456),i=n(448),l=n(453),u=(n(457),{last_modified_on:"2024-01-05",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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. You can retrieve the Kubeconfig of your cluster directly from the Qovery interface by following the procedure "Get your cluster kubeconfig file" ',Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#performing-actions-on-your-clusters"}),"within this section"),".")),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var o=n(0),a=n.n(o),r=n(448);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)}},454:function(e,t,n){"use strict";var o=n(1),a=n(0),r=n.n(a),c=n(39),i=n(458),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}))}},455:function(e,t,n){"use strict";var o=n(459),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("&"):""}},456:function(e,t,n){"use strict";var o=n(0),a=n.n(o),r=(n(447),n(455)),c=n.n(r);n(133);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"),"."))}},457:function(e,t,n){"use strict";var o=n(0),a=n.n(o),r=n(454),c=n(447),i=n.n(c);n(134);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)}},458:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},459: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.8e7073f0.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 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(451)),c=n(458),i=n(450),l=n(455),u=(n(459),{last_modified_on:"2024-01-05",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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. You can retrieve the Kubeconfig of your cluster directly from the Qovery interface by following the procedure "Get your cluster kubeconfig file" ',Object(r.b)("a",Object(o.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/clusters/#performing-actions-on-your-clusters"}),"within this section"),".")),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var o=n(0),a=n.n(o),r=n(450);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)}},456:function(e,t,n){"use strict";var o=n(1),a=n(0),r=n.n(a),c=n(39),i=n(460),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}))}},457:function(e,t,n){"use strict";var o=n(461),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("&"):""}},458:function(e,t,n){"use strict";var o=n(0),a=n.n(o),r=(n(449),n(457)),c=n.n(r);n(133);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"),"."))}},459:function(e,t,n){"use strict";var o=n(0),a=n.n(o),r=n(456),c=n(449),i=n.n(c);n(134);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)}},460:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return o}))},461: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.6e292066.js.LICENSE.txt b/de0a75d9.8e7073f0.js.LICENSE.txt similarity index 100% rename from deef6d59.6e292066.js.LICENSE.txt rename to de0a75d9.8e7073f0.js.LICENSE.txt diff --git a/66bbed7b.533e078b.js b/dea3d534.ca7eee86.js similarity index 94% rename from 66bbed7b.533e078b.js rename to dea3d534.ca7eee86.js index 2c3413f004..58469304ba 100644 --- a/66bbed7b.533e078b.js +++ b/dea3d534.ca7eee86.js @@ -1,2 +1,2 @@ -/*! For license information please see 66bbed7b.533e078b.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 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(449)),i=n(456),c=n(453),l=n(448),s={last_modified_on:"2023-12-20",$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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},455:function(e,t,n){"use strict";var a=n(459),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("&"):""}},456:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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.ca7eee86.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 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(451)),i=n(458),c=n(455),l=n(450),s={last_modified_on:"2023-12-20",$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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},457:function(e,t,n){"use strict";var a=n(461),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("&"):""}},458:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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.ee07c99f.js.LICENSE.txt b/dea3d534.ca7eee86.js.LICENSE.txt similarity index 100% rename from df1c18d8.ee07c99f.js.LICENSE.txt rename to dea3d534.ca7eee86.js.LICENSE.txt diff --git a/deef6d59.6e292066.js b/deef6d59.a4f98fb0.js similarity index 94% rename from deef6d59.6e292066.js rename to deef6d59.a4f98fb0.js index 4958d8970f..0266e80499 100644 --- a/deef6d59.6e292066.js +++ b/deef6d59.a4f98fb0.js @@ -1,2 +1,2 @@ -/*! For license information please see deef6d59.6e292066.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[258],{410: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(449)),i=t(448),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},447: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 +/*! For license information please see deef6d59.a4f98fb0.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[260],{412: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(451)),i=t(450),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},449: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/dfb1c803.130e794d.js.LICENSE.txt b/deef6d59.a4f98fb0.js.LICENSE.txt similarity index 100% rename from dfb1c803.130e794d.js.LICENSE.txt rename to deef6d59.a4f98fb0.js.LICENSE.txt diff --git a/df1c18d8.ee07c99f.js b/df1c18d8.d9a9c6c6.js similarity index 91% rename from df1c18d8.ee07c99f.js rename to df1c18d8.d9a9c6c6.js index 867427ac9d..ff75bff75a 100644 --- a/df1c18d8.ee07c99f.js +++ b/df1c18d8.d9a9c6c6.js @@ -1,2 +1,2 @@ -/*! For license information please see df1c18d8.ee07c99f.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[259],{411:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),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(449)),c=(a(457),a(448)),i=(a(453),{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:"GitOps with Qovery",permalink:"/guides/tutorial/gitops-with-qovery"},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)(c.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)(c.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},447: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):i({},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,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(a),d=n,f=p["".concat(c,".").concat(d)]||p[d]||b[d]||o;return a?r.a.createElement(f,i({ref:t},s,{components:a})):r.a.createElement(f,i({ref:t},s))}));function f(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.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 s=2;s1?arguments[1]:void 0,a),l=c>2?arguments[2]:void 0,s=void 0===l?a:r(l,a);s>i;)t[i++]=e;return t}},452: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""}}})},453:function(e,t,a){"use strict";a(452);var n=a(0),r=a.n(n),o=a(448);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)}},454:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),c=a(39),i=a(458),l=a(20),s=a.n(l);t.a=function(e){var t,a=e.to,l=e.href,u=a||l,p=Object(i.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(c.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}))}},457:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(454),c=a(447),i=a.n(c);a(134);t.a=function(e){var t=e.children,a=e.className,n=e.badge,c=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,p=e.to,b=i()("jump-to","jump-to--"+s,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-"+(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)}},458: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.d9a9c6c6.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[261],{413:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return i})),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(451)),c=(a(459),a(450)),i=(a(455),{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:"GitOps with Qovery",permalink:"/guides/tutorial/gitops-with-qovery"},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)(c.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)(c.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},449: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):i({},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,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=u(a),d=n,f=p["".concat(c,".").concat(d)]||p[d]||b[d]||o;return a?r.a.createElement(f,i({ref:t},s,{components:a})):r.a.createElement(f,i({ref:t},s))}));function f(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.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 s=2;s1?arguments[1]:void 0,a),l=c>2?arguments[2]:void 0,s=void 0===l?a:r(l,a);s>i;)t[i++]=e;return t}},454: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""}}})},455:function(e,t,a){"use strict";a(454);var n=a(0),r=a.n(n),o=a(450);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)}},456:function(e,t,a){"use strict";var n=a(1),r=a(0),o=a.n(r),c=a(39),i=a(460),l=a(20),s=a.n(l);t.a=function(e){var t,a=e.to,l=e.href,u=a||l,p=Object(i.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(c.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}))}},459:function(e,t,a){"use strict";var n=a(0),r=a.n(n),o=a(456),c=a(449),i=a.n(c);a(134);t.a=function(e){var t=e.children,a=e.className,n=e.badge,c=e.leftIcon,l=e.rightIcon,s=e.size,u=e.target,p=e.to,b=i()("jump-to","jump-to--"+s,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-"+(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)}},460: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/dfcfd2f3.8f1f1747.js.LICENSE.txt b/df1c18d8.d9a9c6c6.js.LICENSE.txt similarity index 100% rename from dfcfd2f3.8f1f1747.js.LICENSE.txt rename to df1c18d8.d9a9c6c6.js.LICENSE.txt diff --git a/dfb1c803.130e794d.js b/dfb1c803.dcac8fd1.js similarity index 97% rename from dfb1c803.130e794d.js rename to dfb1c803.dcac8fd1.js index 018ccf265c..5e93a12902 100644 --- a/dfb1c803.130e794d.js +++ b/dfb1c803.dcac8fd1.js @@ -1,2 +1,2 @@ -/*! For license information please see dfb1c803.130e794d.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 s})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return m}));var r=n(1),o=n(9),a=(n(0),n(449)),i=n(448),l=n(453),s=(n(457),{last_modified_on:"2024-07-14",$schema:"/.meta/.schemas/guides.json",title:"GitOps with Qovery",description:"How to do GitOps with Qovery, GitHub and Terraform",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:"GitOps with Qovery",description:"How to do GitOps with Qovery, GitHub and Terraform",permalink:"/guides/tutorial/gitops-with-qovery",readingTime:"16 min read",source:"@site/guides/tutorial/gitops-with-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"GitOps 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:"Grafana setup with Qovery",permalink:"/guides/tutorial/grafana-install"}},p=[{value:"Resources",id:"resources",children:[]},{value:"Terraform vs. YAML",id:"terraform-vs-yaml",children:[]},{value:"Step-by-step tutorial",id:"step-by-step-tutorial",children:[{value:"Step 1: Define the Terraform configuration",id:"step-1-define-the-terraform-configuration",children:[]},{value:"Step 2: Test the Terraform configuration",id:"step-2-test-the-terraform-configuration",children:[]},{value:"Step 3: Push the Terraform configuration to a GitHub repository",id:"step-3-push-the-terraform-configuration-to-a-github-repository",children:[]},{value:"Step 4: Use GitHub Actions to review and apply the Terraform configuration",id:"step-4-use-github-actions-to-review-and-apply-the-terraform-configuration",children:[]},{value:"Step 5: Check the Qovery console to see the resources created",id:"step-5-check-the-qovery-console-to-see-the-resources-created",children:[]}]},{value:"Frequently Asked Questions (FAQ)",id:"frequently-asked-questions-faq",children:[{value:"How to enforce GitOps?",id:"how-to-enforce-gitops",children:[]},{value:"How to "GitOpsify" an existing Qovery configuration?",id:"how-to-gitopsify-an-existing-qovery-configuration",children:[]},{value:"How to see configuration drifts?",id:"how-to-see-configuration-drifts",children:[]},{value:"How to debug?",id:"how-to-debug",children:[]},{value:"How to manage the Terraform state?",id:"how-to-manage-the-terraform-state",children:[]},{value:"How to connect to get Terraform Cloud state?",id:"how-to-connect-to-get-terraform-cloud-state",children:[]},{value:"How to integrate tests?",id:"how-to-integrate-tests",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],u={rightToc:p};function m(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,"GitOps is a way to do Continuous Deployment (CD) with Git. It is a practice that allows you to manage your infrastructure and applications using Git repositories as the source of truth. In this tutorial, you will learn how to do GitOps with Qovery and the Qovery Terraform provider."),Object(a.b)("p",null,"Watch this short video to see the final result:"),Object(a.b)("div",{class:"video-container"},Object(a.b)("p",{align:"center"},Object(a.b)("iframe",{src:"https://www.loom.com/embed/f2b82cd32de8474fae7e8cba2d78dd29",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(a.b)(l.a,{mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"A ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://console.qovery.com/signup"}),"Qovery account")),Object(a.b)("li",{parentName:"ul"},"General knowledge of Terraform"))),Object(a.b)("p",null,"For our example we will do the following with Terraform:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Define all the Qovery resources in a Terraform configuration"),Object(a.b)("li",{parentName:"ol"},"Test it locally"),Object(a.b)("li",{parentName:"ol"},"Push the Terraform configuration to a GitHub repository"),Object(a.b)("li",{parentName:"ol"},"Use GitHub Actions (CI/CD) to review and apply the Terraform configuration"),Object(a.b)("li",{parentName:"ol"},"Check the Qovery console to see the resources created")),Object(a.b)("p",null,"So let's get started!"),Object(a.b)("h2",{id:"resources"},"Resources"),Object(a.b)("p",null,"Here are some resources you might need:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://console.qovery.com"}),"Qovery web console")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli"}),"Terraform CLI")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://registry.terraform.io/providers/Qovery/qovery/latest/docs"}),"Qovery Terraform Provider"))),Object(a.b)("h2",{id:"terraform-vs-yaml"},"Terraform vs. YAML"),Object(a.b)("p",null,"Just before we start, let's talk about why we use Terraform instead of YAML to manage the infrastructure in a GitOps way. Qovery provides an ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://registry.terraform.io/providers/Qovery/qovery/latest/docs"}),"official Terraform provider")," to manage your infrastructure. We did the choice to use Terraform instead of YAML for the following reasons:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Terraform is a well-known tool in the DevOps community"),Object(a.b)("li",{parentName:"ul"},"Terraform gets the state of the infrastructure, which is useful to know what is already created"),Object(a.b)("li",{parentName:"ul"},"Terraform helps to detect drifts between the desired state and the actual state")),Object(a.b)("p",null,"If you are not familiar with Terraform, you can learn more about it on the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.terraform.io/"}),"official website"),"."),Object(a.b)("h2",{id:"step-by-step-tutorial"},"Step-by-step tutorial"),Object(a.b)("p",null,"For this tutorial, we will create a simple Qovery application with a PostgreSQL database. This is just for demo purposes. You can adapt the Terraform configuration to your needs.\nThen We will use Terraform to define the resources and GitHub Actions to apply the Terraform configuration."),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"To enforce GitOps with Qovery, you can limit the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/members-rbac/"}),"permissions")," of your users to read-only in the Qovery console. This way, all the changes will be done via the Terraform configuration.")),Object(a.b)("h3",{id:"step-1-define-the-terraform-configuration"},"Step 1: Define the Terraform configuration"),Object(a.b)("p",null,"Create a new directory and add a ",Object(a.b)("inlineCode",{parentName:"p"},"variables.tf")," and a ",Object(a.b)("inlineCode",{parentName:"p"},"main.tf")," file with the following content:"),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#terraform-exporter"}),"Export your Terraform configuration")," if you have already created your resources with the Qovery web console. ")),Object(a.b)("p",null,Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/evoxmusic/qovery-gitops/blob/main/variables.tf"}),"Read this example on GitHub")),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-hcl",metastring:'title="variables.tf"',title:'"variables.tf"'}),'variable "qovery_token" {\n description = "Qovery API token"\n type = string\n}\n\nvariable "qovery_organization_id" {\n description = "Qovery Organization ID"\n type = string\n}\n\nvariable "qovery_cluster_id" {\n description = "My Qovery Test Cluster ID"\n type = string\n}\n')),Object(a.b)("p",null,Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/evoxmusic/qovery-gitops/blob/main/main.tf"}),"Read this example on GitHub")),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-hcl",metastring:'title="main.tf"',title:'"main.tf"'}),'terraform {\n required_providers {\n qovery = {\n source = "qovery/qovery"\n }\n }\n}\n\nprovider "qovery" {\n token = var.qovery_access_token\n}\n\nresource "qovery_project" "my_project" {\n organization_id = var.qovery_organization_id\n name = "My TF Project"\n}\n\nresource "qovery_environment" "production" {\n project_id = qovery_project.my_project.id\n name = "production"\n mode = "PRODUCTION"\n cluster_id = var.qovery_cluster_id\n}\n\nresource "qovery_database" "my_database" {\n environment_id = qovery_environment.production.id\n name = "My DB"\n type = "POSTGRESQL"\n version = "16"\n mode = "CONTAINER"\n storage = 10\n accessibility = "PRIVATE"\n}\n\nresource "qovery_application" "my_backend" {\n environment_id = qovery_environment.production.id\n name = "My Backend"\n cpu = 250\n memory = 128\n git_repository = {\n url = "https://github.com/evoxmusic/ShortMe-URL-Shortener.git"\n branch = "main"\n root_path = "/"\n }\n build_mode = "DOCKER"\n dockerfile_path = "Dockerfile"\n ports = [\n {\n internal_port = 5555\n external_port = 443\n protocol = "HTTP"\n publicly_accessible = true\n is_default = true\n }\n ]\n healthchecks = {\n readiness_probe = {\n type = {\n http = {\n port = 5555\n scheme = "HTTP"\n path = "/"\n }\n }\n initial_delay_seconds = 30\n period_seconds = 10\n timeout_seconds = 10\n success_threshold = 1\n failure_threshold = 3\n }\n liveness_probe = {\n type = {\n http = {\n port = 5555\n scheme = "HTTP"\n path = "/"\n }\n }\n initial_delay_seconds = 30\n period_seconds = 10\n timeout_seconds = 10\n success_threshold = 1\n failure_threshold = 3\n }\n }\n environment_variables = [\n {\n key = "DATABASE_HOST"\n value = qovery_database.my_database.internal_host\n },\n {\n key = "DATABASE_PORT"\n value = qovery_database.my_database.port\n },\n {\n key = "DATABASE_USERNAME"\n value = qovery_database.my_database.login\n },\n {\n key = "DATABASE_NAME"\n value = "postgres"\n },\n ]\n secrets = [\n {\n key = "DATABASE_PASSWORD"\n value = qovery_database.my_database.password\n }\n ]\n}\n\nresource "qovery_deployment" "my_deployment" {\n environment_id = qovery_environment.production.id\n desired_state = "RUNNING"\n version = "a0282bb4-f5bb-44ed-882d-e067f92d105e"\n\n depends_on = [\n qovery_application.my_backend,\n qovery_database.my_database,\n qovery_environment.production,\n ]\n}\n')),Object(a.b)("p",null,"My arborescence looks like this:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-shell"}),"$ ls -lh\n\nPermissions Size User Date Modified Name\n.rw-r--r-- 2.8k xxx 11 Jul 10:28 main.tf\n.rw-r--r-- 297 xxx 10 Jul 17:24 variables.tf\n")),Object(a.b)("h3",{id:"step-2-test-the-terraform-configuration"},"Step 2: Test the Terraform configuration"),Object(a.b)("h4",{id:"generate-a-qovery-token"},"Generate a Qovery token"),Object(a.b)("p",null,"To test your Terraform configuration, you first need to generate a Qovery token. You can do this by following the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/api-token/"}),"official documentation"),"."),Object(a.b)("h4",{id:"test-terraform-configuration-locally"},"Test Terraform configuration locally"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Download and install ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://developer.hashicorp.com/terraform/install"}),"Terraform CLI")),Object(a.b)("li",{parentName:"ol"},"Set environment variables ",Object(a.b)("ol",{parentName:"li"},Object(a.b)("li",{parentName:"ol"},"Qovery API Token: ",Object(a.b)("inlineCode",{parentName:"li"},"export TF_VAR_qovery_token=XXX")),Object(a.b)("li",{parentName:"ol"},"Qovery Organization ID: ",Object(a.b)("inlineCode",{parentName:"li"},"export TF_VAR_qovery_organization_id=XXX")),Object(a.b)("li",{parentName:"ol"},"Qovery Cluster ID: ",Object(a.b)("inlineCode",{parentName:"li"},"export TF_VAR_qovery_cluster_id=XXX")))),Object(a.b)("li",{parentName:"ol"},"Init Terraform modules: ",Object(a.b)("inlineCode",{parentName:"li"},"terraform init")),Object(a.b)("li",{parentName:"ol"},"Plan the Terraform configuration: ",Object(a.b)("inlineCode",{parentName:"li"},"terraform plan")),Object(a.b)("li",{parentName:"ol"},"Apply the Terraform configuration: ",Object(a.b)("inlineCode",{parentName:"li"},"terraform apply -auto-approve"))),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Test Terraform locally"',title:'"Test',Terraform:!0,'locally"':!0}),"$ export TF_VAR_qovery_token=XXX TF_VAR_qovery_token=XXX TF_VAR_qovery_cluster_id=XXX\n\n$ terraform init && terraform apply -auto-approve\n")),Object(a.b)("p",null,"The output should show the resources created."),Object(a.b)("details",null,Object(a.b)("summary",null,"Example output"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Terraform output"',title:'"Terraform','output"':!0}),'Terraform used the selected providers to generate the following execution plan. Resource actions are\nindicated with the following symbols:\n + create\n\nTerraform will perform the following actions:\n\n # qovery_application.my_backend will be created\n + resource "qovery_application" "my_backend" {\n + advanced_settings_json = (known after apply)\n + arguments = (known after apply)\n + auto_deploy = (known after apply)\n + auto_preview = false\n + build_mode = "DOCKER"\n + built_in_environment_variables = (known after apply)\n + cpu = 250\n + deployment_stage_id = (known after apply)\n + dockerfile_path = "Dockerfile"\n + environment_id = (known after apply)\n + environment_variables = [\n + {\n + id = (known after apply)\n + key = "DATABASE_HOST"\n + value = (known after apply)\n },\n + {\n + id = (known after apply)\n + key = "DATABASE_NAME"\n + value = "postgres"\n },\n + {\n + id = (known after apply)\n + key = "DATABASE_PORT"\n + value = (known after apply)\n },\n + {\n + id = (known after apply)\n + key = "DATABASE_USERNAME"\n + value = (known after apply)\n },\n ]\n + external_host = (known after apply)\n + git_repository = {\n + branch = "main"\n + root_path = "/"\n + url = "https://github.com/evoxmusic/ShortMe-URL-Shortener.git"\n }\n + healthchecks = {\n + liveness_probe = {\n + failure_threshold = 3\n + initial_delay_seconds = 30\n + period_seconds = 10\n + success_threshold = 1\n + timeout_seconds = 10\n + type = {\n + http = {\n + path = "/"\n + port = 5555\n + scheme = "HTTP"\n }\n }\n }\n + readiness_probe = {\n + failure_threshold = 3\n + initial_delay_seconds = 30\n + period_seconds = 10\n + success_threshold = 1\n + timeout_seconds = 10\n + type = {\n + http = {\n + path = "/"\n + port = 5555\n + scheme = "HTTP"\n }\n }\n }\n }\n + id = (known after apply)\n + internal_host = (known after apply)\n + max_running_instances = 1\n + memory = 128\n + min_running_instances = 1\n + name = "My Backend"\n + ports = [\n + {\n + external_port = 443\n + id = (known after apply)\n + internal_port = 5555\n + is_default = true\n + name = (known after apply)\n + protocol = "HTTP"\n + publicly_accessible = true\n },\n ]\n + secrets = (sensitive value)\n }\n\n # qovery_database.my_database will be created\n + resource "qovery_database" "my_database" {\n + accessibility = "PRIVATE"\n + cpu = 250\n + deployment_stage_id = (known after apply)\n + environment_id = (known after apply)\n + external_host = (known after apply)\n + id = (known after apply)\n + instance_type = (known after apply)\n + internal_host = (known after apply)\n + login = (known after apply)\n + memory = 256\n + mode = "CONTAINER"\n + name = "My DB"\n + password = (known after apply)\n + port = (known after apply)\n + storage = 10\n + type = "POSTGRESQL"\n + version = "16"\n }\n\n # qovery_deployment.my_deployment will be created\n + resource "qovery_deployment" "my_deployment" {\n + desired_state = "RUNNING"\n + environment_id = (known after apply)\n + id = (known after apply)\n + version = "a0282bb4-f5bb-44ed-882d-e067f92d106e"\n }\n\n # qovery_environment.production will be created\n + resource "qovery_environment" "production" {\n + built_in_environment_variables = (known after apply)\n + cluster_id = "809f9644-b3e4-400b-97fc-e2173d46a00e"\n + id = (known after apply)\n + mode = "PRODUCTION"\n + name = "production"\n + project_id = (known after apply)\n }\n\n # qovery_project.my_project will be created\n + resource "qovery_project" "my_project" {\n + built_in_environment_variables = (known after apply)\n + description = (known after apply)\n + id = (known after apply)\n + name = "My TF Project"\n + organization_id = "141c07c8-0dd9-4623-983b-3fdd61867255"\n }\n\nPlan: 5 to add, 0 to change, 0 to destroy.\nqovery_project.my_project: Creating...\nqovery_project.my_project: Creation complete after 1s [id=66ad165a-f7f8-4840-8519-8db11ae7d127]\nqovery_environment.production: Creating...\nqovery_environment.production: Creation complete after 1s [id=a51a7e66-af37-425a-92a7-c07b9f1752fc]\nqovery_database.my_database: Creating...\nqovery_database.my_database: Creation complete after 2s [id=454b5baa-1465-4383-a822-32f1511222a0]\nqovery_application.my_backend: Creating...\nqovery_application.my_backend: Creation complete after 3s [id=a4ff2488-ad6a-4218-9e52-68aa3ebdd059]\nqovery_deployment.my_deployment: Creating...\nqovery_deployment.my_deployment: Still creating... [10s elapsed]\nqovery_deployment.my_deployment: Still creating... [20s elapsed]\nqovery_deployment.my_deployment: Still creating... [30s elapsed]\nqovery_deployment.my_deployment: Still creating... [40s elapsed]\nqovery_deployment.my_deployment: Still creating... [50s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m0s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m10s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m20s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m30s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m40s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m50s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m0s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m10s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m20s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m30s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m40s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m50s elapsed]\nqovery_deployment.my_deployment: Still creating... [3m0s elapsed]\nqovery_deployment.my_deployment: Still creating... [3m10s elapsed]\nqovery_deployment.my_deployment: Still creating... [3m20s elapsed]\nqovery_deployment.my_deployment: Creation complete after 3m24s [id=84435485-eb50-4051-b91f-61f99985edf2]\n\nApply complete! Resources: 5 added, 0 changed, 0 destroyed.\n'))),Object(a.b)("p",null,"If you edit resources in the Terraform configuration, you can re-apply the changes with ",Object(a.b)("inlineCode",{parentName:"p"},"terraform apply -auto-approve"),". Note that for service resources, when you change the configuration, you need to redeploy them by updating the ",Object(a.b)("inlineCode",{parentName:"p"},"qovery_deployment.version")," UUID."),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Once you have tested your Terraform configuration locally, you must clean up the resources with ",Object(a.b)("inlineCode",{parentName:"p"},"terraform destroy -auto-approve")," since we will use our CI/CD tool to apply the Terraform configuration and a remote Terraform backend to store the state.")),Object(a.b)("h3",{id:"step-3-push-the-terraform-configuration-to-a-github-repository"},"Step 3: Push the Terraform configuration to a GitHub repository"),Object(a.b)("p",null,"Since we have tested the Terraform configuration locally, we can now push it to your Git repository. In my case, I will use GitHub."),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Create a Git repository"),Object(a.b)("li",{parentName:"ol"},"Commit and push the Terraform configuration to the repository")),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Make sure to add the ",Object(a.b)("inlineCode",{parentName:"p"},".terraform")," directory and other generated terraform metafiles to your ",Object(a.b)("inlineCode",{parentName:"p"},".gitignore")," file.")),Object(a.b)("p",null,"Here is a .gitignore you can use:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-gitignore",metastring:'title=".gitignore"',title:'".gitignore"'}),"# Local .terraform directories\n**/.terraform/*\n\n# .tfstate files\n*.tfstate\n*.tfstate.*\n\n# Crash log files\ncrash.log\ncrash.*.log\n\n# Exclude all .tfvars files, which are likely to contain sensitive data, such as\n# password, private keys, and other secrets. These should not be part of version \n# control as they are data points which are potentially sensitive and subject \n# to change depending on the environment.\n*.tfvars\n*.tfvars.json\n\n# Ignore override files as they are usually used to override resources locally and so\n# are not checked in\noverride.tf\noverride.tf.json\n*_override.tf\n*_override.tf.json\n\n# Include override files you do wish to add to version control using negated pattern\n# !example_override.tf\n\n# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan\n# example: *tfplan*\n\n# Ignore CLI configuration files\n.terraformrc\nterraform.rc\n")),Object(a.b)("h3",{id:"step-4-use-github-actions-to-review-and-apply-the-terraform-configuration"},"Step 4: Use GitHub Actions to review and apply the Terraform configuration"),Object(a.b)("p",null,"In my case, I will use:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://github.com/features/actions"}),"GitHub Actions")," as a CI tool to review and apply the Terraform."),Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://www.hashicorp.com/cloud"}),"Hashicorp Cloud Platform")," as a Terraform backend state. ")),Object(a.b)("p",null,"Note that you can use any CI/CD tool and Terraform backend you want."),Object(a.b)("p",null,Object(a.b)("em",{parentName:"p"},"This section is inspired by the official ",Object(a.b)("a",Object(r.a)({parentName:"em"},{href:"https://developer.hashicorp.com/terraform/tutorials/automation/github-actions"}),"Terraform GitHub Actions documentation"),".")),Object(a.b)("p",null,"Here is an example of a GitHub Actions workflow (",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/evoxmusic/qovery-gitops/blob/main/.github/workflows/terraform-plan.yml"}),"GitHub Link"),") when a Pull Request is created:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-yaml",metastring:'title=".github/workflows/terraform-plan.yml"',title:'".github/workflows/terraform-plan.yml"'}),'name: "Terraform Plan"\n\non:\n pull_request:\n\nenv:\n TF_CLOUD_ORGANIZATION: "YOUR-ORGANIZATION-HERE"\n TF_API_TOKEN: "${{ secrets.TF_API_TOKEN }}"\n TF_WORKSPACE: "YOUR-WORKSPACE-HERE"\n CONFIG_DIRECTORY: "./"\n\njobs:\n terraform:\n name: "Terraform Plan"\n runs-on: ubuntu-latest\n permissions:\n contents: read\n pull-requests: write\n steps:\n - name: Checkout\n uses: actions/checkout@v3\n\n - name: Upload Configuration\n uses: hashicorp/tfc-workflows-github/actions/upload-configuration@v1.0.0\n id: plan-upload\n with:\n workspace: ${{ env.TF_WORKSPACE }}\n directory: ${{ env.CONFIG_DIRECTORY }}\n speculative: true\n\n - name: Create Plan Run\n uses: hashicorp/tfc-workflows-github/actions/create-run@v1.0.0\n id: plan-run\n with:\n workspace: ${{ env.TF_WORKSPACE }}\n configuration_version: ${{ steps.plan-upload.outputs.configuration_version_id }}\n plan_only: true\n\n - name: Get Plan Output\n uses: hashicorp/tfc-workflows-github/actions/plan-output@v1.0.0\n id: plan-output\n with:\n plan: ${{ fromJSON(steps.plan-run.outputs.payload).data.relationships.plan.data.id }}\n\n - name: Update PR\n uses: actions/github-script@v6\n id: plan-comment\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n // 1. Retrieve existing bot comments for the PR\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n const botComment = comments.find(comment => {\n return comment.user.type === \'Bot\' && comment.body.includes(\'Terraform Cloud Plan Output\')\n });\n const output = `#### Terraform Cloud Plan Output\n \\`\\`\\`\n Plan: ${{ steps.plan-output.outputs.add }} to add, ${{ steps.plan-output.outputs.change }} to change, ${{ steps.plan-output.outputs.destroy }} to destroy.\n \\`\\`\\`\n [Terraform Cloud Plan](${{ steps.plan-run.outputs.run_link }})\n `;\n // 3. Delete previous comment so PR timeline makes sense\n if (botComment) {\n github.rest.issues.deleteComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n });\n }\n github.rest.issues.createComment({\n issue_number: context.issue.number,\n owner: context.repo.owner,\n repo: context.repo.repo,\n body: output\n });\n')),Object(a.b)("p",null,"When a Pull Request is created, the GitHub Actions workflow will run the Terraform plan and post the output in the PR comments. So you can ",Object(a.b)("strong",{parentName:"p"},"review the changes")," before merging the PR."),Object(a.b)("p",null,"Here is an example of a GitHub Actions workflow (",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/evoxmusic/qovery-gitops/blob/main/.github/workflows/terraform-plan.yml"}),"GitHub Link"),") when the PR is merged:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-yaml",metastring:'title=".github/workflows/terraform-apply.yml"',title:'".github/workflows/terraform-apply.yml"'}),'name: "Terraform Apply"\n\non:\n push:\n branches:\n - main\n\nenv:\n TF_CLOUD_ORGANIZATION: "YOUR-ORGANIZATION-HERE"\n TF_API_TOKEN: "${{ secrets.TF_API_TOKEN }}"\n TF_WORKSPACE: "YOUR-WORKSPACE-HERE"\n CONFIG_DIRECTORY: "./"\n\njobs:\n terraform:\n name: "Terraform Apply"\n runs-on: ubuntu-latest\n permissions:\n contents: read\n steps:\n - name: Checkout\n uses: actions/checkout@v3\n\n - name: Upload Configuration\n uses: hashicorp/tfc-workflows-github/actions/upload-configuration@v1.0.0\n id: apply-upload\n with:\n workspace: ${{ env.TF_WORKSPACE }}\n directory: ${{ env.CONFIG_DIRECTORY }}\n\n - name: Create Apply Run\n uses: hashicorp/tfc-workflows-github/actions/create-run@v1.0.0\n id: apply-run\n with:\n workspace: ${{ env.TF_WORKSPACE }}\n configuration_version: ${{ steps.apply-upload.outputs.configuration_version_id }}\n\n - name: Apply\n uses: hashicorp/tfc-workflows-github/actions/apply-run@v1.0.0\n if: fromJSON(steps.apply-run.outputs.payload).data.attributes.actions.IsConfirmable\n id: apply\n with:\n run: ${{ steps.apply-run.outputs.run_id }}\n comment: "Apply Run from GitHub Actions CI ${{ github.sha }}"\n')),Object(a.b)("p",null,"When the PR is merged on the main branch, the GitHub Actions workflow will apply the Terraform configuration."),Object(a.b)("h3",{id:"step-5-check-the-qovery-console-to-see-the-resources-created"},"Step 5: Check the Qovery console to see the resources created"),Object(a.b)("p",null,"After the GitHub Actions workflow is completed, you can check the Qovery console to see the resources created."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/resources-created-with-terraform.jpg",alt:"Qovery resources created via Terraform in a GitOps way"})),Object(a.b)("p",null,"As you can see, you can manage your infrastructure and applications using Git repositories as the source of truth with Qovery and Terraform."),Object(a.b)("h2",{id:"frequently-asked-questions-faq"},"Frequently Asked Questions (FAQ)"),Object(a.b)("h3",{id:"how-to-enforce-gitops"},"How to enforce GitOps?"),Object(a.b)("p",null,"Here are the two things we recommend to enforce GitOps with Qovery:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/members-rbac/"}),"Restrict permissions")," of your users to read-only in Qovery. So only the API Qovery Token used by Terraform will be able to create, update, or delete resources. "),Object(a.b)("li",{parentName:"ol"},"Turn off the ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"application auto-deployment")," in Qovery. If you have linked apps via Git with Qovery, you can turn off the auto-deployment.")),Object(a.b)("p",null,"This way, all the changes will be done via the Terraform configuration."),Object(a.b)("h3",{id:"how-to-gitopsify-an-existing-qovery-configuration"},'How to "GitOpsify" an existing Qovery configuration?'),Object(a.b)("p",null,"To make your existing configuration GitOps compatible, you can follow these steps:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Export your existing Qovery configuration with the ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/environment/#terraform-exporter"}),"Terraform exporter"),"."),Object(a.b)("li",{parentName:"ol"},"Edit your exported Terraform configuration."),Object(a.b)("li",{parentName:"ol"},"Test the Terraform configuration locally."),Object(a.b)("li",{parentName:"ol"},"Push the Terraform configuration to a Git repository.")),Object(a.b)("h3",{id:"how-to-see-configuration-drifts"},"How to see configuration drifts?"),Object(a.b)("p",null,"Terraform helps to detect drifts between the desired state and the actual state. When you will create a Pull Request, the GitHub Actions workflow will run the Terraform plan and post the output in the PR comments. So you can review the changes before merging the PR. "),Object(a.b)("p",null,"You can also use the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform plan")," locally command to see the changes that will be applied."),Object(a.b)("h3",{id:"how-to-debug"},"How to debug?"),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Terraform logs"),":\nLet's say you have a problem with the Terraform configuration. You can debug it by checking the Terraform logs in the GitHub Actions workflow. You can also use the Terraform CLI to debug the configuration locally."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Application logs"),":\nIf the problem is not in the Terraform configuration, you can check the Qovery web console to see the resources created and the associated ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/"}),"logs"),"."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"CI/CD logs"),":\nYou can check the GitHub Actions logs to see the Terraform plan and apply outputs."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Qovery logs"),":\nYou can check the Qovery ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/audit-logs/"}),"Audit Logs")," to see the changes made by the Terraform configuration."),Object(a.b)("h3",{id:"how-to-manage-the-terraform-state"},"How to manage the Terraform state?"),Object(a.b)("p",null,"Like in the example above, we recommend using a remote Terraform backend to store the state. This way, you can share the state between your team members and have a history of the changes. You can use the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.hashicorp.com/cloud"}),"Hashicorp Cloud Platform")," or any other Terraform backend you want."),Object(a.b)("h3",{id:"how-to-connect-to-get-terraform-cloud-state"},"How to connect to get Terraform Cloud state?"),Object(a.b)("p",null,"Create a ",Object(a.b)("inlineCode",{parentName:"p"},"backend.tf")," file in your Terraform configuration with the following content:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-hcl",metastring:'title="backend.tf"',title:'"backend.tf"'}),'terraform {\n backend "remote" {\n hostname = "app.terraform.io"\n organization = "Qovery"\n workspaces {\n name = "qovery-gitops"\n }\n }\n}\n')),Object(a.b)("p",null,"Refer to ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://support.hashicorp.com/hc/en-us/articles/360001151948-Migrate-Workspace-State-Using-Terraform-State-Push-Pull"}),"this documentation")),Object(a.b)("h3",{id:"how-to-integrate-tests"},"How to integrate tests?"),Object(a.b)("p",null,"You can use the Qovery API to get the resources URLs and integrate them in your CI/CD. For example, you can get the URL of the application and use it in your tests. Look at this guide on ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/build-e2e-testing-ephemeral-environments/"}),"how to run E2E tests with Qovery and GitHub Actions"),"."),Object(a.b)("h2",{id:"conclusion"},"Conclusion"),Object(a.b)("p",null,"In this tutorial, you learned how to do GitOps with Qovery and the Qovery Terraform provider. You defined all the Qovery resources in a Terraform configuration, tested it locally, pushed it to a GitHub repository, used GitHub Actions to review and apply the Terraform configuration, and checked the Qovery console to see the resources created."),Object(a.b)("p",null,"If you have any questions or need help, feel free to ask in the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Qovery Community Forum"),"."))}m.isMDXComponent=!0},447: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 c=o.a.createContext({}),p=function(e){var t=o.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 o.a.createElement(c.Provider,{value:t},e.children)},m={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,c=s(e,["components","mdxType","originalType","parentName"]),u=p(n),d=r,b=u["".concat(i,".").concat(d)]||u[d]||m[d]||a;return n?o.a.createElement(b,l({ref:t},c,{components:n})):o.a.createElement(b,l({ref:t},c))}));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]=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:r,i[1]=l;for(var c=2;c1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,c=void 0===s?n:o(s,n);c>l;)t[l++]=e;return t}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},454:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),l=n(458),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),m=Object(o.useRef)(!1),d=c.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(p),function(){d&&t&&t.disconnect()}}),[p,d,u]),p&&u?a.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(p),m.current=!0)},innerRef:function(e){var n,r;d&&e&&u&&(n=e,r=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(),r())}))}))).observe(n))},to:p})):a.a.createElement("a",Object(r.a)({},e,{href:p}))}},457:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(454),i=n(447),l=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,s=e.rightIcon,c=e.size,p=e.target,u=e.to,m=l()("jump-to","jump-to--"+c,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-"+(s||"chevron-right")+" arrow"}))));return p?o.a.createElement("a",{href:u,target:p,className:m},d):o.a.createElement(a.a,{to:u,className:m},d)}},458: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 dfb1c803.dcac8fd1.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 s})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return m}));var r=n(1),o=n(9),a=(n(0),n(451)),i=n(450),l=n(455),s=(n(459),{last_modified_on:"2024-07-14",$schema:"/.meta/.schemas/guides.json",title:"GitOps with Qovery",description:"How to do GitOps with Qovery, GitHub and Terraform",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:"GitOps with Qovery",description:"How to do GitOps with Qovery, GitHub and Terraform",permalink:"/guides/tutorial/gitops-with-qovery",readingTime:"16 min read",source:"@site/guides/tutorial/gitops-with-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"GitOps 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:"Grafana setup with Qovery",permalink:"/guides/tutorial/grafana-install"}},p=[{value:"Resources",id:"resources",children:[]},{value:"Terraform vs. YAML",id:"terraform-vs-yaml",children:[]},{value:"Step-by-step tutorial",id:"step-by-step-tutorial",children:[{value:"Step 1: Define the Terraform configuration",id:"step-1-define-the-terraform-configuration",children:[]},{value:"Step 2: Test the Terraform configuration",id:"step-2-test-the-terraform-configuration",children:[]},{value:"Step 3: Push the Terraform configuration to a GitHub repository",id:"step-3-push-the-terraform-configuration-to-a-github-repository",children:[]},{value:"Step 4: Use GitHub Actions to review and apply the Terraform configuration",id:"step-4-use-github-actions-to-review-and-apply-the-terraform-configuration",children:[]},{value:"Step 5: Check the Qovery console to see the resources created",id:"step-5-check-the-qovery-console-to-see-the-resources-created",children:[]}]},{value:"Frequently Asked Questions (FAQ)",id:"frequently-asked-questions-faq",children:[{value:"How to enforce GitOps?",id:"how-to-enforce-gitops",children:[]},{value:"How to "GitOpsify" an existing Qovery configuration?",id:"how-to-gitopsify-an-existing-qovery-configuration",children:[]},{value:"How to see configuration drifts?",id:"how-to-see-configuration-drifts",children:[]},{value:"How to debug?",id:"how-to-debug",children:[]},{value:"How to manage the Terraform state?",id:"how-to-manage-the-terraform-state",children:[]},{value:"How to connect to get Terraform Cloud state?",id:"how-to-connect-to-get-terraform-cloud-state",children:[]},{value:"How to integrate tests?",id:"how-to-integrate-tests",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],u={rightToc:p};function m(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,"GitOps is a way to do Continuous Deployment (CD) with Git. It is a practice that allows you to manage your infrastructure and applications using Git repositories as the source of truth. In this tutorial, you will learn how to do GitOps with Qovery and the Qovery Terraform provider."),Object(a.b)("p",null,"Watch this short video to see the final result:"),Object(a.b)("div",{class:"video-container"},Object(a.b)("p",{align:"center"},Object(a.b)("iframe",{src:"https://www.loom.com/embed/f2b82cd32de8474fae7e8cba2d78dd29",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(a.b)(l.a,{mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"A ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://console.qovery.com/signup"}),"Qovery account")),Object(a.b)("li",{parentName:"ul"},"General knowledge of Terraform"))),Object(a.b)("p",null,"For our example we will do the following with Terraform:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Define all the Qovery resources in a Terraform configuration"),Object(a.b)("li",{parentName:"ol"},"Test it locally"),Object(a.b)("li",{parentName:"ol"},"Push the Terraform configuration to a GitHub repository"),Object(a.b)("li",{parentName:"ol"},"Use GitHub Actions (CI/CD) to review and apply the Terraform configuration"),Object(a.b)("li",{parentName:"ol"},"Check the Qovery console to see the resources created")),Object(a.b)("p",null,"So let's get started!"),Object(a.b)("h2",{id:"resources"},"Resources"),Object(a.b)("p",null,"Here are some resources you might need:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://console.qovery.com"}),"Qovery web console")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli"}),"Terraform CLI")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://registry.terraform.io/providers/Qovery/qovery/latest/docs"}),"Qovery Terraform Provider"))),Object(a.b)("h2",{id:"terraform-vs-yaml"},"Terraform vs. YAML"),Object(a.b)("p",null,"Just before we start, let's talk about why we use Terraform instead of YAML to manage the infrastructure in a GitOps way. Qovery provides an ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://registry.terraform.io/providers/Qovery/qovery/latest/docs"}),"official Terraform provider")," to manage your infrastructure. We did the choice to use Terraform instead of YAML for the following reasons:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Terraform is a well-known tool in the DevOps community"),Object(a.b)("li",{parentName:"ul"},"Terraform gets the state of the infrastructure, which is useful to know what is already created"),Object(a.b)("li",{parentName:"ul"},"Terraform helps to detect drifts between the desired state and the actual state")),Object(a.b)("p",null,"If you are not familiar with Terraform, you can learn more about it on the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.terraform.io/"}),"official website"),"."),Object(a.b)("h2",{id:"step-by-step-tutorial"},"Step-by-step tutorial"),Object(a.b)("p",null,"For this tutorial, we will create a simple Qovery application with a PostgreSQL database. This is just for demo purposes. You can adapt the Terraform configuration to your needs.\nThen We will use Terraform to define the resources and GitHub Actions to apply the Terraform configuration."),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"To enforce GitOps with Qovery, you can limit the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/members-rbac/"}),"permissions")," of your users to read-only in the Qovery console. This way, all the changes will be done via the Terraform configuration.")),Object(a.b)("h3",{id:"step-1-define-the-terraform-configuration"},"Step 1: Define the Terraform configuration"),Object(a.b)("p",null,"Create a new directory and add a ",Object(a.b)("inlineCode",{parentName:"p"},"variables.tf")," and a ",Object(a.b)("inlineCode",{parentName:"p"},"main.tf")," file with the following content:"),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#terraform-exporter"}),"Export your Terraform configuration")," if you have already created your resources with the Qovery web console. ")),Object(a.b)("p",null,Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/evoxmusic/qovery-gitops/blob/main/variables.tf"}),"Read this example on GitHub")),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-hcl",metastring:'title="variables.tf"',title:'"variables.tf"'}),'variable "qovery_token" {\n description = "Qovery API token"\n type = string\n}\n\nvariable "qovery_organization_id" {\n description = "Qovery Organization ID"\n type = string\n}\n\nvariable "qovery_cluster_id" {\n description = "My Qovery Test Cluster ID"\n type = string\n}\n')),Object(a.b)("p",null,Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/evoxmusic/qovery-gitops/blob/main/main.tf"}),"Read this example on GitHub")),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-hcl",metastring:'title="main.tf"',title:'"main.tf"'}),'terraform {\n required_providers {\n qovery = {\n source = "qovery/qovery"\n }\n }\n}\n\nprovider "qovery" {\n token = var.qovery_access_token\n}\n\nresource "qovery_project" "my_project" {\n organization_id = var.qovery_organization_id\n name = "My TF Project"\n}\n\nresource "qovery_environment" "production" {\n project_id = qovery_project.my_project.id\n name = "production"\n mode = "PRODUCTION"\n cluster_id = var.qovery_cluster_id\n}\n\nresource "qovery_database" "my_database" {\n environment_id = qovery_environment.production.id\n name = "My DB"\n type = "POSTGRESQL"\n version = "16"\n mode = "CONTAINER"\n storage = 10\n accessibility = "PRIVATE"\n}\n\nresource "qovery_application" "my_backend" {\n environment_id = qovery_environment.production.id\n name = "My Backend"\n cpu = 250\n memory = 128\n git_repository = {\n url = "https://github.com/evoxmusic/ShortMe-URL-Shortener.git"\n branch = "main"\n root_path = "/"\n }\n build_mode = "DOCKER"\n dockerfile_path = "Dockerfile"\n ports = [\n {\n internal_port = 5555\n external_port = 443\n protocol = "HTTP"\n publicly_accessible = true\n is_default = true\n }\n ]\n healthchecks = {\n readiness_probe = {\n type = {\n http = {\n port = 5555\n scheme = "HTTP"\n path = "/"\n }\n }\n initial_delay_seconds = 30\n period_seconds = 10\n timeout_seconds = 10\n success_threshold = 1\n failure_threshold = 3\n }\n liveness_probe = {\n type = {\n http = {\n port = 5555\n scheme = "HTTP"\n path = "/"\n }\n }\n initial_delay_seconds = 30\n period_seconds = 10\n timeout_seconds = 10\n success_threshold = 1\n failure_threshold = 3\n }\n }\n environment_variables = [\n {\n key = "DATABASE_HOST"\n value = qovery_database.my_database.internal_host\n },\n {\n key = "DATABASE_PORT"\n value = qovery_database.my_database.port\n },\n {\n key = "DATABASE_USERNAME"\n value = qovery_database.my_database.login\n },\n {\n key = "DATABASE_NAME"\n value = "postgres"\n },\n ]\n secrets = [\n {\n key = "DATABASE_PASSWORD"\n value = qovery_database.my_database.password\n }\n ]\n}\n\nresource "qovery_deployment" "my_deployment" {\n environment_id = qovery_environment.production.id\n desired_state = "RUNNING"\n version = "a0282bb4-f5bb-44ed-882d-e067f92d105e"\n\n depends_on = [\n qovery_application.my_backend,\n qovery_database.my_database,\n qovery_environment.production,\n ]\n}\n')),Object(a.b)("p",null,"My arborescence looks like this:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-shell"}),"$ ls -lh\n\nPermissions Size User Date Modified Name\n.rw-r--r-- 2.8k xxx 11 Jul 10:28 main.tf\n.rw-r--r-- 297 xxx 10 Jul 17:24 variables.tf\n")),Object(a.b)("h3",{id:"step-2-test-the-terraform-configuration"},"Step 2: Test the Terraform configuration"),Object(a.b)("h4",{id:"generate-a-qovery-token"},"Generate a Qovery token"),Object(a.b)("p",null,"To test your Terraform configuration, you first need to generate a Qovery token. You can do this by following the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/api-token/"}),"official documentation"),"."),Object(a.b)("h4",{id:"test-terraform-configuration-locally"},"Test Terraform configuration locally"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Download and install ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://developer.hashicorp.com/terraform/install"}),"Terraform CLI")),Object(a.b)("li",{parentName:"ol"},"Set environment variables ",Object(a.b)("ol",{parentName:"li"},Object(a.b)("li",{parentName:"ol"},"Qovery API Token: ",Object(a.b)("inlineCode",{parentName:"li"},"export TF_VAR_qovery_token=XXX")),Object(a.b)("li",{parentName:"ol"},"Qovery Organization ID: ",Object(a.b)("inlineCode",{parentName:"li"},"export TF_VAR_qovery_organization_id=XXX")),Object(a.b)("li",{parentName:"ol"},"Qovery Cluster ID: ",Object(a.b)("inlineCode",{parentName:"li"},"export TF_VAR_qovery_cluster_id=XXX")))),Object(a.b)("li",{parentName:"ol"},"Init Terraform modules: ",Object(a.b)("inlineCode",{parentName:"li"},"terraform init")),Object(a.b)("li",{parentName:"ol"},"Plan the Terraform configuration: ",Object(a.b)("inlineCode",{parentName:"li"},"terraform plan")),Object(a.b)("li",{parentName:"ol"},"Apply the Terraform configuration: ",Object(a.b)("inlineCode",{parentName:"li"},"terraform apply -auto-approve"))),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Test Terraform locally"',title:'"Test',Terraform:!0,'locally"':!0}),"$ export TF_VAR_qovery_token=XXX TF_VAR_qovery_token=XXX TF_VAR_qovery_cluster_id=XXX\n\n$ terraform init && terraform apply -auto-approve\n")),Object(a.b)("p",null,"The output should show the resources created."),Object(a.b)("details",null,Object(a.b)("summary",null,"Example output"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Terraform output"',title:'"Terraform','output"':!0}),'Terraform used the selected providers to generate the following execution plan. Resource actions are\nindicated with the following symbols:\n + create\n\nTerraform will perform the following actions:\n\n # qovery_application.my_backend will be created\n + resource "qovery_application" "my_backend" {\n + advanced_settings_json = (known after apply)\n + arguments = (known after apply)\n + auto_deploy = (known after apply)\n + auto_preview = false\n + build_mode = "DOCKER"\n + built_in_environment_variables = (known after apply)\n + cpu = 250\n + deployment_stage_id = (known after apply)\n + dockerfile_path = "Dockerfile"\n + environment_id = (known after apply)\n + environment_variables = [\n + {\n + id = (known after apply)\n + key = "DATABASE_HOST"\n + value = (known after apply)\n },\n + {\n + id = (known after apply)\n + key = "DATABASE_NAME"\n + value = "postgres"\n },\n + {\n + id = (known after apply)\n + key = "DATABASE_PORT"\n + value = (known after apply)\n },\n + {\n + id = (known after apply)\n + key = "DATABASE_USERNAME"\n + value = (known after apply)\n },\n ]\n + external_host = (known after apply)\n + git_repository = {\n + branch = "main"\n + root_path = "/"\n + url = "https://github.com/evoxmusic/ShortMe-URL-Shortener.git"\n }\n + healthchecks = {\n + liveness_probe = {\n + failure_threshold = 3\n + initial_delay_seconds = 30\n + period_seconds = 10\n + success_threshold = 1\n + timeout_seconds = 10\n + type = {\n + http = {\n + path = "/"\n + port = 5555\n + scheme = "HTTP"\n }\n }\n }\n + readiness_probe = {\n + failure_threshold = 3\n + initial_delay_seconds = 30\n + period_seconds = 10\n + success_threshold = 1\n + timeout_seconds = 10\n + type = {\n + http = {\n + path = "/"\n + port = 5555\n + scheme = "HTTP"\n }\n }\n }\n }\n + id = (known after apply)\n + internal_host = (known after apply)\n + max_running_instances = 1\n + memory = 128\n + min_running_instances = 1\n + name = "My Backend"\n + ports = [\n + {\n + external_port = 443\n + id = (known after apply)\n + internal_port = 5555\n + is_default = true\n + name = (known after apply)\n + protocol = "HTTP"\n + publicly_accessible = true\n },\n ]\n + secrets = (sensitive value)\n }\n\n # qovery_database.my_database will be created\n + resource "qovery_database" "my_database" {\n + accessibility = "PRIVATE"\n + cpu = 250\n + deployment_stage_id = (known after apply)\n + environment_id = (known after apply)\n + external_host = (known after apply)\n + id = (known after apply)\n + instance_type = (known after apply)\n + internal_host = (known after apply)\n + login = (known after apply)\n + memory = 256\n + mode = "CONTAINER"\n + name = "My DB"\n + password = (known after apply)\n + port = (known after apply)\n + storage = 10\n + type = "POSTGRESQL"\n + version = "16"\n }\n\n # qovery_deployment.my_deployment will be created\n + resource "qovery_deployment" "my_deployment" {\n + desired_state = "RUNNING"\n + environment_id = (known after apply)\n + id = (known after apply)\n + version = "a0282bb4-f5bb-44ed-882d-e067f92d106e"\n }\n\n # qovery_environment.production will be created\n + resource "qovery_environment" "production" {\n + built_in_environment_variables = (known after apply)\n + cluster_id = "809f9644-b3e4-400b-97fc-e2173d46a00e"\n + id = (known after apply)\n + mode = "PRODUCTION"\n + name = "production"\n + project_id = (known after apply)\n }\n\n # qovery_project.my_project will be created\n + resource "qovery_project" "my_project" {\n + built_in_environment_variables = (known after apply)\n + description = (known after apply)\n + id = (known after apply)\n + name = "My TF Project"\n + organization_id = "141c07c8-0dd9-4623-983b-3fdd61867255"\n }\n\nPlan: 5 to add, 0 to change, 0 to destroy.\nqovery_project.my_project: Creating...\nqovery_project.my_project: Creation complete after 1s [id=66ad165a-f7f8-4840-8519-8db11ae7d127]\nqovery_environment.production: Creating...\nqovery_environment.production: Creation complete after 1s [id=a51a7e66-af37-425a-92a7-c07b9f1752fc]\nqovery_database.my_database: Creating...\nqovery_database.my_database: Creation complete after 2s [id=454b5baa-1465-4383-a822-32f1511222a0]\nqovery_application.my_backend: Creating...\nqovery_application.my_backend: Creation complete after 3s [id=a4ff2488-ad6a-4218-9e52-68aa3ebdd059]\nqovery_deployment.my_deployment: Creating...\nqovery_deployment.my_deployment: Still creating... [10s elapsed]\nqovery_deployment.my_deployment: Still creating... [20s elapsed]\nqovery_deployment.my_deployment: Still creating... [30s elapsed]\nqovery_deployment.my_deployment: Still creating... [40s elapsed]\nqovery_deployment.my_deployment: Still creating... [50s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m0s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m10s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m20s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m30s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m40s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m50s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m0s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m10s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m20s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m30s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m40s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m50s elapsed]\nqovery_deployment.my_deployment: Still creating... [3m0s elapsed]\nqovery_deployment.my_deployment: Still creating... [3m10s elapsed]\nqovery_deployment.my_deployment: Still creating... [3m20s elapsed]\nqovery_deployment.my_deployment: Creation complete after 3m24s [id=84435485-eb50-4051-b91f-61f99985edf2]\n\nApply complete! Resources: 5 added, 0 changed, 0 destroyed.\n'))),Object(a.b)("p",null,"If you edit resources in the Terraform configuration, you can re-apply the changes with ",Object(a.b)("inlineCode",{parentName:"p"},"terraform apply -auto-approve"),". Note that for service resources, when you change the configuration, you need to redeploy them by updating the ",Object(a.b)("inlineCode",{parentName:"p"},"qovery_deployment.version")," UUID."),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Once you have tested your Terraform configuration locally, you must clean up the resources with ",Object(a.b)("inlineCode",{parentName:"p"},"terraform destroy -auto-approve")," since we will use our CI/CD tool to apply the Terraform configuration and a remote Terraform backend to store the state.")),Object(a.b)("h3",{id:"step-3-push-the-terraform-configuration-to-a-github-repository"},"Step 3: Push the Terraform configuration to a GitHub repository"),Object(a.b)("p",null,"Since we have tested the Terraform configuration locally, we can now push it to your Git repository. In my case, I will use GitHub."),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Create a Git repository"),Object(a.b)("li",{parentName:"ol"},"Commit and push the Terraform configuration to the repository")),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Make sure to add the ",Object(a.b)("inlineCode",{parentName:"p"},".terraform")," directory and other generated terraform metafiles to your ",Object(a.b)("inlineCode",{parentName:"p"},".gitignore")," file.")),Object(a.b)("p",null,"Here is a .gitignore you can use:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-gitignore",metastring:'title=".gitignore"',title:'".gitignore"'}),"# Local .terraform directories\n**/.terraform/*\n\n# .tfstate files\n*.tfstate\n*.tfstate.*\n\n# Crash log files\ncrash.log\ncrash.*.log\n\n# Exclude all .tfvars files, which are likely to contain sensitive data, such as\n# password, private keys, and other secrets. These should not be part of version \n# control as they are data points which are potentially sensitive and subject \n# to change depending on the environment.\n*.tfvars\n*.tfvars.json\n\n# Ignore override files as they are usually used to override resources locally and so\n# are not checked in\noverride.tf\noverride.tf.json\n*_override.tf\n*_override.tf.json\n\n# Include override files you do wish to add to version control using negated pattern\n# !example_override.tf\n\n# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan\n# example: *tfplan*\n\n# Ignore CLI configuration files\n.terraformrc\nterraform.rc\n")),Object(a.b)("h3",{id:"step-4-use-github-actions-to-review-and-apply-the-terraform-configuration"},"Step 4: Use GitHub Actions to review and apply the Terraform configuration"),Object(a.b)("p",null,"In my case, I will use:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://github.com/features/actions"}),"GitHub Actions")," as a CI tool to review and apply the Terraform."),Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://www.hashicorp.com/cloud"}),"Hashicorp Cloud Platform")," as a Terraform backend state. ")),Object(a.b)("p",null,"Note that you can use any CI/CD tool and Terraform backend you want."),Object(a.b)("p",null,Object(a.b)("em",{parentName:"p"},"This section is inspired by the official ",Object(a.b)("a",Object(r.a)({parentName:"em"},{href:"https://developer.hashicorp.com/terraform/tutorials/automation/github-actions"}),"Terraform GitHub Actions documentation"),".")),Object(a.b)("p",null,"Here is an example of a GitHub Actions workflow (",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/evoxmusic/qovery-gitops/blob/main/.github/workflows/terraform-plan.yml"}),"GitHub Link"),") when a Pull Request is created:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-yaml",metastring:'title=".github/workflows/terraform-plan.yml"',title:'".github/workflows/terraform-plan.yml"'}),'name: "Terraform Plan"\n\non:\n pull_request:\n\nenv:\n TF_CLOUD_ORGANIZATION: "YOUR-ORGANIZATION-HERE"\n TF_API_TOKEN: "${{ secrets.TF_API_TOKEN }}"\n TF_WORKSPACE: "YOUR-WORKSPACE-HERE"\n CONFIG_DIRECTORY: "./"\n\njobs:\n terraform:\n name: "Terraform Plan"\n runs-on: ubuntu-latest\n permissions:\n contents: read\n pull-requests: write\n steps:\n - name: Checkout\n uses: actions/checkout@v3\n\n - name: Upload Configuration\n uses: hashicorp/tfc-workflows-github/actions/upload-configuration@v1.0.0\n id: plan-upload\n with:\n workspace: ${{ env.TF_WORKSPACE }}\n directory: ${{ env.CONFIG_DIRECTORY }}\n speculative: true\n\n - name: Create Plan Run\n uses: hashicorp/tfc-workflows-github/actions/create-run@v1.0.0\n id: plan-run\n with:\n workspace: ${{ env.TF_WORKSPACE }}\n configuration_version: ${{ steps.plan-upload.outputs.configuration_version_id }}\n plan_only: true\n\n - name: Get Plan Output\n uses: hashicorp/tfc-workflows-github/actions/plan-output@v1.0.0\n id: plan-output\n with:\n plan: ${{ fromJSON(steps.plan-run.outputs.payload).data.relationships.plan.data.id }}\n\n - name: Update PR\n uses: actions/github-script@v6\n id: plan-comment\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n // 1. Retrieve existing bot comments for the PR\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n const botComment = comments.find(comment => {\n return comment.user.type === \'Bot\' && comment.body.includes(\'Terraform Cloud Plan Output\')\n });\n const output = `#### Terraform Cloud Plan Output\n \\`\\`\\`\n Plan: ${{ steps.plan-output.outputs.add }} to add, ${{ steps.plan-output.outputs.change }} to change, ${{ steps.plan-output.outputs.destroy }} to destroy.\n \\`\\`\\`\n [Terraform Cloud Plan](${{ steps.plan-run.outputs.run_link }})\n `;\n // 3. Delete previous comment so PR timeline makes sense\n if (botComment) {\n github.rest.issues.deleteComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n });\n }\n github.rest.issues.createComment({\n issue_number: context.issue.number,\n owner: context.repo.owner,\n repo: context.repo.repo,\n body: output\n });\n')),Object(a.b)("p",null,"When a Pull Request is created, the GitHub Actions workflow will run the Terraform plan and post the output in the PR comments. So you can ",Object(a.b)("strong",{parentName:"p"},"review the changes")," before merging the PR."),Object(a.b)("p",null,"Here is an example of a GitHub Actions workflow (",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/evoxmusic/qovery-gitops/blob/main/.github/workflows/terraform-plan.yml"}),"GitHub Link"),") when the PR is merged:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-yaml",metastring:'title=".github/workflows/terraform-apply.yml"',title:'".github/workflows/terraform-apply.yml"'}),'name: "Terraform Apply"\n\non:\n push:\n branches:\n - main\n\nenv:\n TF_CLOUD_ORGANIZATION: "YOUR-ORGANIZATION-HERE"\n TF_API_TOKEN: "${{ secrets.TF_API_TOKEN }}"\n TF_WORKSPACE: "YOUR-WORKSPACE-HERE"\n CONFIG_DIRECTORY: "./"\n\njobs:\n terraform:\n name: "Terraform Apply"\n runs-on: ubuntu-latest\n permissions:\n contents: read\n steps:\n - name: Checkout\n uses: actions/checkout@v3\n\n - name: Upload Configuration\n uses: hashicorp/tfc-workflows-github/actions/upload-configuration@v1.0.0\n id: apply-upload\n with:\n workspace: ${{ env.TF_WORKSPACE }}\n directory: ${{ env.CONFIG_DIRECTORY }}\n\n - name: Create Apply Run\n uses: hashicorp/tfc-workflows-github/actions/create-run@v1.0.0\n id: apply-run\n with:\n workspace: ${{ env.TF_WORKSPACE }}\n configuration_version: ${{ steps.apply-upload.outputs.configuration_version_id }}\n\n - name: Apply\n uses: hashicorp/tfc-workflows-github/actions/apply-run@v1.0.0\n if: fromJSON(steps.apply-run.outputs.payload).data.attributes.actions.IsConfirmable\n id: apply\n with:\n run: ${{ steps.apply-run.outputs.run_id }}\n comment: "Apply Run from GitHub Actions CI ${{ github.sha }}"\n')),Object(a.b)("p",null,"When the PR is merged on the main branch, the GitHub Actions workflow will apply the Terraform configuration."),Object(a.b)("h3",{id:"step-5-check-the-qovery-console-to-see-the-resources-created"},"Step 5: Check the Qovery console to see the resources created"),Object(a.b)("p",null,"After the GitHub Actions workflow is completed, you can check the Qovery console to see the resources created."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/resources-created-with-terraform.jpg",alt:"Qovery resources created via Terraform in a GitOps way"})),Object(a.b)("p",null,"As you can see, you can manage your infrastructure and applications using Git repositories as the source of truth with Qovery and Terraform."),Object(a.b)("h2",{id:"frequently-asked-questions-faq"},"Frequently Asked Questions (FAQ)"),Object(a.b)("h3",{id:"how-to-enforce-gitops"},"How to enforce GitOps?"),Object(a.b)("p",null,"Here are the two things we recommend to enforce GitOps with Qovery:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/members-rbac/"}),"Restrict permissions")," of your users to read-only in Qovery. So only the API Qovery Token used by Terraform will be able to create, update, or delete resources. "),Object(a.b)("li",{parentName:"ol"},"Turn off the ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"application auto-deployment")," in Qovery. If you have linked apps via Git with Qovery, you can turn off the auto-deployment.")),Object(a.b)("p",null,"This way, all the changes will be done via the Terraform configuration."),Object(a.b)("h3",{id:"how-to-gitopsify-an-existing-qovery-configuration"},'How to "GitOpsify" an existing Qovery configuration?'),Object(a.b)("p",null,"To make your existing configuration GitOps compatible, you can follow these steps:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Export your existing Qovery configuration with the ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/environment/#terraform-exporter"}),"Terraform exporter"),"."),Object(a.b)("li",{parentName:"ol"},"Edit your exported Terraform configuration."),Object(a.b)("li",{parentName:"ol"},"Test the Terraform configuration locally."),Object(a.b)("li",{parentName:"ol"},"Push the Terraform configuration to a Git repository.")),Object(a.b)("h3",{id:"how-to-see-configuration-drifts"},"How to see configuration drifts?"),Object(a.b)("p",null,"Terraform helps to detect drifts between the desired state and the actual state. When you will create a Pull Request, the GitHub Actions workflow will run the Terraform plan and post the output in the PR comments. So you can review the changes before merging the PR. "),Object(a.b)("p",null,"You can also use the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform plan")," locally command to see the changes that will be applied."),Object(a.b)("h3",{id:"how-to-debug"},"How to debug?"),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Terraform logs"),":\nLet's say you have a problem with the Terraform configuration. You can debug it by checking the Terraform logs in the GitHub Actions workflow. You can also use the Terraform CLI to debug the configuration locally."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Application logs"),":\nIf the problem is not in the Terraform configuration, you can check the Qovery web console to see the resources created and the associated ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/"}),"logs"),"."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"CI/CD logs"),":\nYou can check the GitHub Actions logs to see the Terraform plan and apply outputs."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Qovery logs"),":\nYou can check the Qovery ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/audit-logs/"}),"Audit Logs")," to see the changes made by the Terraform configuration."),Object(a.b)("h3",{id:"how-to-manage-the-terraform-state"},"How to manage the Terraform state?"),Object(a.b)("p",null,"Like in the example above, we recommend using a remote Terraform backend to store the state. This way, you can share the state between your team members and have a history of the changes. You can use the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.hashicorp.com/cloud"}),"Hashicorp Cloud Platform")," or any other Terraform backend you want."),Object(a.b)("h3",{id:"how-to-connect-to-get-terraform-cloud-state"},"How to connect to get Terraform Cloud state?"),Object(a.b)("p",null,"Create a ",Object(a.b)("inlineCode",{parentName:"p"},"backend.tf")," file in your Terraform configuration with the following content:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-hcl",metastring:'title="backend.tf"',title:'"backend.tf"'}),'terraform {\n backend "remote" {\n hostname = "app.terraform.io"\n organization = "Qovery"\n workspaces {\n name = "qovery-gitops"\n }\n }\n}\n')),Object(a.b)("p",null,"Refer to ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://support.hashicorp.com/hc/en-us/articles/360001151948-Migrate-Workspace-State-Using-Terraform-State-Push-Pull"}),"this documentation")),Object(a.b)("h3",{id:"how-to-integrate-tests"},"How to integrate tests?"),Object(a.b)("p",null,"You can use the Qovery API to get the resources URLs and integrate them in your CI/CD. For example, you can get the URL of the application and use it in your tests. Look at this guide on ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/build-e2e-testing-ephemeral-environments/"}),"how to run E2E tests with Qovery and GitHub Actions"),"."),Object(a.b)("h2",{id:"conclusion"},"Conclusion"),Object(a.b)("p",null,"In this tutorial, you learned how to do GitOps with Qovery and the Qovery Terraform provider. You defined all the Qovery resources in a Terraform configuration, tested it locally, pushed it to a GitHub repository, used GitHub Actions to review and apply the Terraform configuration, and checked the Qovery console to see the resources created."),Object(a.b)("p",null,"If you have any questions or need help, feel free to ask in the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Qovery Community Forum"),"."))}m.isMDXComponent=!0},449: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 c=o.a.createContext({}),p=function(e){var t=o.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 o.a.createElement(c.Provider,{value:t},e.children)},m={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,c=s(e,["components","mdxType","originalType","parentName"]),u=p(n),d=r,b=u["".concat(i,".").concat(d)]||u[d]||m[d]||a;return n?o.a.createElement(b,l({ref:t},c,{components:n})):o.a.createElement(b,l({ref:t},c))}));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]=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:r,i[1]=l;for(var c=2;c1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,c=void 0===s?n:o(s,n);c>l;)t[l++]=e;return t}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},456:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),l=n(460),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),m=Object(o.useRef)(!1),d=c.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(p),function(){d&&t&&t.disconnect()}}),[p,d,u]),p&&u?a.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(p),m.current=!0)},innerRef:function(e){var n,r;d&&e&&u&&(n=e,r=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(),r())}))}))).observe(n))},to:p})):a.a.createElement("a",Object(r.a)({},e,{href:p}))}},459:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(456),i=n(449),l=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,s=e.rightIcon,c=e.size,p=e.target,u=e.to,m=l()("jump-to","jump-to--"+c,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-"+(s||"chevron-right")+" arrow"}))));return p?o.a.createElement("a",{href:u,target:p,className:m},d):o.a.createElement(a.a,{to:u,className:m},d)}},460: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/dffbf523.17aebafc.js.LICENSE.txt b/dfb1c803.dcac8fd1.js.LICENSE.txt similarity index 100% rename from dffbf523.17aebafc.js.LICENSE.txt rename to dfb1c803.dcac8fd1.js.LICENSE.txt diff --git a/dfcfd2f3.8f1f1747.js b/dfcfd2f3.236e52c4.js similarity index 97% rename from dfcfd2f3.8f1f1747.js rename to dfcfd2f3.236e52c4.js index 739e6c700b..b66bb4bcc5 100644 --- a/dfcfd2f3.8f1f1747.js +++ b/dfcfd2f3.236e52c4.js @@ -1,2 +1,2 @@ -/*! For license information please see dfcfd2f3.8f1f1747.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 s})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return p})),n.d(t,"default",(function(){return m}));var r=n(1),o=n(9),a=(n(0),n(449)),i=n(448),l=n(453),s=(n(457),{last_modified_on:"2024-07-14",$schema:"/.meta/.schemas/guides.json",title:"GitOps with Qovery",description:"How to do GitOps with Qovery, GitHub and Terraform",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:"GitOps with Qovery",description:"How to do GitOps with Qovery, GitHub and Terraform",permalink:"/guides/tutorial/gitops-with-qovery",readingTime:"16 min read",source:"@site/guides/tutorial/gitops-with-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"GitOps 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:"Grafana setup with Qovery",permalink:"/guides/tutorial/grafana-install"}},p=[{value:"Resources",id:"resources",children:[]},{value:"Terraform vs. YAML",id:"terraform-vs-yaml",children:[]},{value:"Step-by-step tutorial",id:"step-by-step-tutorial",children:[{value:"Step 1: Define the Terraform configuration",id:"step-1-define-the-terraform-configuration",children:[]},{value:"Step 2: Test the Terraform configuration",id:"step-2-test-the-terraform-configuration",children:[]},{value:"Step 3: Push the Terraform configuration to a GitHub repository",id:"step-3-push-the-terraform-configuration-to-a-github-repository",children:[]},{value:"Step 4: Use GitHub Actions to review and apply the Terraform configuration",id:"step-4-use-github-actions-to-review-and-apply-the-terraform-configuration",children:[]},{value:"Step 5: Check the Qovery console to see the resources created",id:"step-5-check-the-qovery-console-to-see-the-resources-created",children:[]}]},{value:"Frequently Asked Questions (FAQ)",id:"frequently-asked-questions-faq",children:[{value:"How to enforce GitOps?",id:"how-to-enforce-gitops",children:[]},{value:"How to "GitOpsify" an existing Qovery configuration?",id:"how-to-gitopsify-an-existing-qovery-configuration",children:[]},{value:"How to see configuration drifts?",id:"how-to-see-configuration-drifts",children:[]},{value:"How to debug?",id:"how-to-debug",children:[]},{value:"How to manage the Terraform state?",id:"how-to-manage-the-terraform-state",children:[]},{value:"How to connect to get Terraform Cloud state?",id:"how-to-connect-to-get-terraform-cloud-state",children:[]},{value:"How to integrate tests?",id:"how-to-integrate-tests",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],u={rightToc:p};function m(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,"GitOps is a way to do Continuous Deployment (CD) with Git. It is a practice that allows you to manage your infrastructure and applications using Git repositories as the source of truth. In this tutorial, you will learn how to do GitOps with Qovery and the Qovery Terraform provider."),Object(a.b)("p",null,"Watch this short video to see the final result:"),Object(a.b)("div",{class:"video-container"},Object(a.b)("p",{align:"center"},Object(a.b)("iframe",{src:"https://www.loom.com/embed/f2b82cd32de8474fae7e8cba2d78dd29",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(a.b)(l.a,{mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"A ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://console.qovery.com/signup"}),"Qovery account")),Object(a.b)("li",{parentName:"ul"},"General knowledge of Terraform"))),Object(a.b)("p",null,"For our example we will do the following with Terraform:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Define all the Qovery resources in a Terraform configuration"),Object(a.b)("li",{parentName:"ol"},"Test it locally"),Object(a.b)("li",{parentName:"ol"},"Push the Terraform configuration to a GitHub repository"),Object(a.b)("li",{parentName:"ol"},"Use GitHub Actions (CI/CD) to review and apply the Terraform configuration"),Object(a.b)("li",{parentName:"ol"},"Check the Qovery console to see the resources created")),Object(a.b)("p",null,"So let's get started!"),Object(a.b)("h2",{id:"resources"},"Resources"),Object(a.b)("p",null,"Here are some resources you might need:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://console.qovery.com"}),"Qovery web console")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli"}),"Terraform CLI")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://registry.terraform.io/providers/Qovery/qovery/latest/docs"}),"Qovery Terraform Provider"))),Object(a.b)("h2",{id:"terraform-vs-yaml"},"Terraform vs. YAML"),Object(a.b)("p",null,"Just before we start, let's talk about why we use Terraform instead of YAML to manage the infrastructure in a GitOps way. Qovery provides an ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://registry.terraform.io/providers/Qovery/qovery/latest/docs"}),"official Terraform provider")," to manage your infrastructure. We did the choice to use Terraform instead of YAML for the following reasons:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Terraform is a well-known tool in the DevOps community"),Object(a.b)("li",{parentName:"ul"},"Terraform gets the state of the infrastructure, which is useful to know what is already created"),Object(a.b)("li",{parentName:"ul"},"Terraform helps to detect drifts between the desired state and the actual state")),Object(a.b)("p",null,"If you are not familiar with Terraform, you can learn more about it on the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.terraform.io/"}),"official website"),"."),Object(a.b)("h2",{id:"step-by-step-tutorial"},"Step-by-step tutorial"),Object(a.b)("p",null,"For this tutorial, we will create a simple Qovery application with a PostgreSQL database. This is just for demo purposes. You can adapt the Terraform configuration to your needs.\nThen We will use Terraform to define the resources and GitHub Actions to apply the Terraform configuration."),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"To enforce GitOps with Qovery, you can limit the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/members-rbac/"}),"permissions")," of your users to read-only in the Qovery console. This way, all the changes will be done via the Terraform configuration.")),Object(a.b)("h3",{id:"step-1-define-the-terraform-configuration"},"Step 1: Define the Terraform configuration"),Object(a.b)("p",null,"Create a new directory and add a ",Object(a.b)("inlineCode",{parentName:"p"},"variables.tf")," and a ",Object(a.b)("inlineCode",{parentName:"p"},"main.tf")," file with the following content:"),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#terraform-exporter"}),"Export your Terraform configuration")," if you have already created your resources with the Qovery web console. ")),Object(a.b)("p",null,Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/evoxmusic/qovery-gitops/blob/main/variables.tf"}),"Read this example on GitHub")),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-hcl",metastring:'title="variables.tf"',title:'"variables.tf"'}),'variable "qovery_token" {\n description = "Qovery API token"\n type = string\n}\n\nvariable "qovery_organization_id" {\n description = "Qovery Organization ID"\n type = string\n}\n\nvariable "qovery_cluster_id" {\n description = "My Qovery Test Cluster ID"\n type = string\n}\n')),Object(a.b)("p",null,Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/evoxmusic/qovery-gitops/blob/main/main.tf"}),"Read this example on GitHub")),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-hcl",metastring:'title="main.tf"',title:'"main.tf"'}),'terraform {\n required_providers {\n qovery = {\n source = "qovery/qovery"\n }\n }\n}\n\nprovider "qovery" {\n token = var.qovery_access_token\n}\n\nresource "qovery_project" "my_project" {\n organization_id = var.qovery_organization_id\n name = "My TF Project"\n}\n\nresource "qovery_environment" "production" {\n project_id = qovery_project.my_project.id\n name = "production"\n mode = "PRODUCTION"\n cluster_id = var.qovery_cluster_id\n}\n\nresource "qovery_database" "my_database" {\n environment_id = qovery_environment.production.id\n name = "My DB"\n type = "POSTGRESQL"\n version = "16"\n mode = "CONTAINER"\n storage = 10\n accessibility = "PRIVATE"\n}\n\nresource "qovery_application" "my_backend" {\n environment_id = qovery_environment.production.id\n name = "My Backend"\n cpu = 250\n memory = 128\n git_repository = {\n url = "https://github.com/evoxmusic/ShortMe-URL-Shortener.git"\n branch = "main"\n root_path = "/"\n }\n build_mode = "DOCKER"\n dockerfile_path = "Dockerfile"\n ports = [\n {\n internal_port = 5555\n external_port = 443\n protocol = "HTTP"\n publicly_accessible = true\n is_default = true\n }\n ]\n healthchecks = {\n readiness_probe = {\n type = {\n http = {\n port = 5555\n scheme = "HTTP"\n path = "/"\n }\n }\n initial_delay_seconds = 30\n period_seconds = 10\n timeout_seconds = 10\n success_threshold = 1\n failure_threshold = 3\n }\n liveness_probe = {\n type = {\n http = {\n port = 5555\n scheme = "HTTP"\n path = "/"\n }\n }\n initial_delay_seconds = 30\n period_seconds = 10\n timeout_seconds = 10\n success_threshold = 1\n failure_threshold = 3\n }\n }\n environment_variables = [\n {\n key = "DATABASE_HOST"\n value = qovery_database.my_database.internal_host\n },\n {\n key = "DATABASE_PORT"\n value = qovery_database.my_database.port\n },\n {\n key = "DATABASE_USERNAME"\n value = qovery_database.my_database.login\n },\n {\n key = "DATABASE_NAME"\n value = "postgres"\n },\n ]\n secrets = [\n {\n key = "DATABASE_PASSWORD"\n value = qovery_database.my_database.password\n }\n ]\n}\n\nresource "qovery_deployment" "my_deployment" {\n environment_id = qovery_environment.production.id\n desired_state = "RUNNING"\n version = "a0282bb4-f5bb-44ed-882d-e067f92d105e"\n\n depends_on = [\n qovery_application.my_backend,\n qovery_database.my_database,\n qovery_environment.production,\n ]\n}\n')),Object(a.b)("p",null,"My arborescence looks like this:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-shell"}),"$ ls -lh\n\nPermissions Size User Date Modified Name\n.rw-r--r-- 2.8k xxx 11 Jul 10:28 main.tf\n.rw-r--r-- 297 xxx 10 Jul 17:24 variables.tf\n")),Object(a.b)("h3",{id:"step-2-test-the-terraform-configuration"},"Step 2: Test the Terraform configuration"),Object(a.b)("h4",{id:"generate-a-qovery-token"},"Generate a Qovery token"),Object(a.b)("p",null,"To test your Terraform configuration, you first need to generate a Qovery token. You can do this by following the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/api-token/"}),"official documentation"),"."),Object(a.b)("h4",{id:"test-terraform-configuration-locally"},"Test Terraform configuration locally"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Download and install ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://developer.hashicorp.com/terraform/install"}),"Terraform CLI")),Object(a.b)("li",{parentName:"ol"},"Set environment variables ",Object(a.b)("ol",{parentName:"li"},Object(a.b)("li",{parentName:"ol"},"Qovery API Token: ",Object(a.b)("inlineCode",{parentName:"li"},"export TF_VAR_qovery_token=XXX")),Object(a.b)("li",{parentName:"ol"},"Qovery Organization ID: ",Object(a.b)("inlineCode",{parentName:"li"},"export TF_VAR_qovery_organization_id=XXX")),Object(a.b)("li",{parentName:"ol"},"Qovery Cluster ID: ",Object(a.b)("inlineCode",{parentName:"li"},"export TF_VAR_qovery_cluster_id=XXX")))),Object(a.b)("li",{parentName:"ol"},"Init Terraform modules: ",Object(a.b)("inlineCode",{parentName:"li"},"terraform init")),Object(a.b)("li",{parentName:"ol"},"Plan the Terraform configuration: ",Object(a.b)("inlineCode",{parentName:"li"},"terraform plan")),Object(a.b)("li",{parentName:"ol"},"Apply the Terraform configuration: ",Object(a.b)("inlineCode",{parentName:"li"},"terraform apply -auto-approve"))),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Test Terraform locally"',title:'"Test',Terraform:!0,'locally"':!0}),"$ export TF_VAR_qovery_token=XXX TF_VAR_qovery_token=XXX TF_VAR_qovery_cluster_id=XXX\n\n$ terraform init && terraform apply -auto-approve\n")),Object(a.b)("p",null,"The output should show the resources created."),Object(a.b)("details",null,Object(a.b)("summary",null,"Example output"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Terraform output"',title:'"Terraform','output"':!0}),'Terraform used the selected providers to generate the following execution plan. Resource actions are\nindicated with the following symbols:\n + create\n\nTerraform will perform the following actions:\n\n # qovery_application.my_backend will be created\n + resource "qovery_application" "my_backend" {\n + advanced_settings_json = (known after apply)\n + arguments = (known after apply)\n + auto_deploy = (known after apply)\n + auto_preview = false\n + build_mode = "DOCKER"\n + built_in_environment_variables = (known after apply)\n + cpu = 250\n + deployment_stage_id = (known after apply)\n + dockerfile_path = "Dockerfile"\n + environment_id = (known after apply)\n + environment_variables = [\n + {\n + id = (known after apply)\n + key = "DATABASE_HOST"\n + value = (known after apply)\n },\n + {\n + id = (known after apply)\n + key = "DATABASE_NAME"\n + value = "postgres"\n },\n + {\n + id = (known after apply)\n + key = "DATABASE_PORT"\n + value = (known after apply)\n },\n + {\n + id = (known after apply)\n + key = "DATABASE_USERNAME"\n + value = (known after apply)\n },\n ]\n + external_host = (known after apply)\n + git_repository = {\n + branch = "main"\n + root_path = "/"\n + url = "https://github.com/evoxmusic/ShortMe-URL-Shortener.git"\n }\n + healthchecks = {\n + liveness_probe = {\n + failure_threshold = 3\n + initial_delay_seconds = 30\n + period_seconds = 10\n + success_threshold = 1\n + timeout_seconds = 10\n + type = {\n + http = {\n + path = "/"\n + port = 5555\n + scheme = "HTTP"\n }\n }\n }\n + readiness_probe = {\n + failure_threshold = 3\n + initial_delay_seconds = 30\n + period_seconds = 10\n + success_threshold = 1\n + timeout_seconds = 10\n + type = {\n + http = {\n + path = "/"\n + port = 5555\n + scheme = "HTTP"\n }\n }\n }\n }\n + id = (known after apply)\n + internal_host = (known after apply)\n + max_running_instances = 1\n + memory = 128\n + min_running_instances = 1\n + name = "My Backend"\n + ports = [\n + {\n + external_port = 443\n + id = (known after apply)\n + internal_port = 5555\n + is_default = true\n + name = (known after apply)\n + protocol = "HTTP"\n + publicly_accessible = true\n },\n ]\n + secrets = (sensitive value)\n }\n\n # qovery_database.my_database will be created\n + resource "qovery_database" "my_database" {\n + accessibility = "PRIVATE"\n + cpu = 250\n + deployment_stage_id = (known after apply)\n + environment_id = (known after apply)\n + external_host = (known after apply)\n + id = (known after apply)\n + instance_type = (known after apply)\n + internal_host = (known after apply)\n + login = (known after apply)\n + memory = 256\n + mode = "CONTAINER"\n + name = "My DB"\n + password = (known after apply)\n + port = (known after apply)\n + storage = 10\n + type = "POSTGRESQL"\n + version = "16"\n }\n\n # qovery_deployment.my_deployment will be created\n + resource "qovery_deployment" "my_deployment" {\n + desired_state = "RUNNING"\n + environment_id = (known after apply)\n + id = (known after apply)\n + version = "a0282bb4-f5bb-44ed-882d-e067f92d106e"\n }\n\n # qovery_environment.production will be created\n + resource "qovery_environment" "production" {\n + built_in_environment_variables = (known after apply)\n + cluster_id = "809f9644-b3e4-400b-97fc-e2173d46a00e"\n + id = (known after apply)\n + mode = "PRODUCTION"\n + name = "production"\n + project_id = (known after apply)\n }\n\n # qovery_project.my_project will be created\n + resource "qovery_project" "my_project" {\n + built_in_environment_variables = (known after apply)\n + description = (known after apply)\n + id = (known after apply)\n + name = "My TF Project"\n + organization_id = "141c07c8-0dd9-4623-983b-3fdd61867255"\n }\n\nPlan: 5 to add, 0 to change, 0 to destroy.\nqovery_project.my_project: Creating...\nqovery_project.my_project: Creation complete after 1s [id=66ad165a-f7f8-4840-8519-8db11ae7d127]\nqovery_environment.production: Creating...\nqovery_environment.production: Creation complete after 1s [id=a51a7e66-af37-425a-92a7-c07b9f1752fc]\nqovery_database.my_database: Creating...\nqovery_database.my_database: Creation complete after 2s [id=454b5baa-1465-4383-a822-32f1511222a0]\nqovery_application.my_backend: Creating...\nqovery_application.my_backend: Creation complete after 3s [id=a4ff2488-ad6a-4218-9e52-68aa3ebdd059]\nqovery_deployment.my_deployment: Creating...\nqovery_deployment.my_deployment: Still creating... [10s elapsed]\nqovery_deployment.my_deployment: Still creating... [20s elapsed]\nqovery_deployment.my_deployment: Still creating... [30s elapsed]\nqovery_deployment.my_deployment: Still creating... [40s elapsed]\nqovery_deployment.my_deployment: Still creating... [50s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m0s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m10s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m20s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m30s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m40s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m50s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m0s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m10s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m20s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m30s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m40s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m50s elapsed]\nqovery_deployment.my_deployment: Still creating... [3m0s elapsed]\nqovery_deployment.my_deployment: Still creating... [3m10s elapsed]\nqovery_deployment.my_deployment: Still creating... [3m20s elapsed]\nqovery_deployment.my_deployment: Creation complete after 3m24s [id=84435485-eb50-4051-b91f-61f99985edf2]\n\nApply complete! Resources: 5 added, 0 changed, 0 destroyed.\n'))),Object(a.b)("p",null,"If you edit resources in the Terraform configuration, you can re-apply the changes with ",Object(a.b)("inlineCode",{parentName:"p"},"terraform apply -auto-approve"),". Note that for service resources, when you change the configuration, you need to redeploy them by updating the ",Object(a.b)("inlineCode",{parentName:"p"},"qovery_deployment.version")," UUID."),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Once you have tested your Terraform configuration locally, you must clean up the resources with ",Object(a.b)("inlineCode",{parentName:"p"},"terraform destroy -auto-approve")," since we will use our CI/CD tool to apply the Terraform configuration and a remote Terraform backend to store the state.")),Object(a.b)("h3",{id:"step-3-push-the-terraform-configuration-to-a-github-repository"},"Step 3: Push the Terraform configuration to a GitHub repository"),Object(a.b)("p",null,"Since we have tested the Terraform configuration locally, we can now push it to your Git repository. In my case, I will use GitHub."),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Create a Git repository"),Object(a.b)("li",{parentName:"ol"},"Commit and push the Terraform configuration to the repository")),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Make sure to add the ",Object(a.b)("inlineCode",{parentName:"p"},".terraform")," directory and other generated terraform metafiles to your ",Object(a.b)("inlineCode",{parentName:"p"},".gitignore")," file.")),Object(a.b)("p",null,"Here is a .gitignore you can use:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-gitignore",metastring:'title=".gitignore"',title:'".gitignore"'}),"# Local .terraform directories\n**/.terraform/*\n\n# .tfstate files\n*.tfstate\n*.tfstate.*\n\n# Crash log files\ncrash.log\ncrash.*.log\n\n# Exclude all .tfvars files, which are likely to contain sensitive data, such as\n# password, private keys, and other secrets. These should not be part of version \n# control as they are data points which are potentially sensitive and subject \n# to change depending on the environment.\n*.tfvars\n*.tfvars.json\n\n# Ignore override files as they are usually used to override resources locally and so\n# are not checked in\noverride.tf\noverride.tf.json\n*_override.tf\n*_override.tf.json\n\n# Include override files you do wish to add to version control using negated pattern\n# !example_override.tf\n\n# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan\n# example: *tfplan*\n\n# Ignore CLI configuration files\n.terraformrc\nterraform.rc\n")),Object(a.b)("h3",{id:"step-4-use-github-actions-to-review-and-apply-the-terraform-configuration"},"Step 4: Use GitHub Actions to review and apply the Terraform configuration"),Object(a.b)("p",null,"In my case, I will use:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://github.com/features/actions"}),"GitHub Actions")," as a CI tool to review and apply the Terraform."),Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://www.hashicorp.com/cloud"}),"Hashicorp Cloud Platform")," as a Terraform backend state. ")),Object(a.b)("p",null,"Note that you can use any CI/CD tool and Terraform backend you want."),Object(a.b)("p",null,Object(a.b)("em",{parentName:"p"},"This section is inspired by the official ",Object(a.b)("a",Object(r.a)({parentName:"em"},{href:"https://developer.hashicorp.com/terraform/tutorials/automation/github-actions"}),"Terraform GitHub Actions documentation"),".")),Object(a.b)("p",null,"Here is an example of a GitHub Actions workflow (",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/evoxmusic/qovery-gitops/blob/main/.github/workflows/terraform-plan.yml"}),"GitHub Link"),") when a Pull Request is created:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-yaml",metastring:'title=".github/workflows/terraform-plan.yml"',title:'".github/workflows/terraform-plan.yml"'}),'name: "Terraform Plan"\n\non:\n pull_request:\n\nenv:\n TF_CLOUD_ORGANIZATION: "YOUR-ORGANIZATION-HERE"\n TF_API_TOKEN: "${{ secrets.TF_API_TOKEN }}"\n TF_WORKSPACE: "YOUR-WORKSPACE-HERE"\n CONFIG_DIRECTORY: "./"\n\njobs:\n terraform:\n name: "Terraform Plan"\n runs-on: ubuntu-latest\n permissions:\n contents: read\n pull-requests: write\n steps:\n - name: Checkout\n uses: actions/checkout@v3\n\n - name: Upload Configuration\n uses: hashicorp/tfc-workflows-github/actions/upload-configuration@v1.0.0\n id: plan-upload\n with:\n workspace: ${{ env.TF_WORKSPACE }}\n directory: ${{ env.CONFIG_DIRECTORY }}\n speculative: true\n\n - name: Create Plan Run\n uses: hashicorp/tfc-workflows-github/actions/create-run@v1.0.0\n id: plan-run\n with:\n workspace: ${{ env.TF_WORKSPACE }}\n configuration_version: ${{ steps.plan-upload.outputs.configuration_version_id }}\n plan_only: true\n\n - name: Get Plan Output\n uses: hashicorp/tfc-workflows-github/actions/plan-output@v1.0.0\n id: plan-output\n with:\n plan: ${{ fromJSON(steps.plan-run.outputs.payload).data.relationships.plan.data.id }}\n\n - name: Update PR\n uses: actions/github-script@v6\n id: plan-comment\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n // 1. Retrieve existing bot comments for the PR\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n const botComment = comments.find(comment => {\n return comment.user.type === \'Bot\' && comment.body.includes(\'Terraform Cloud Plan Output\')\n });\n const output = `#### Terraform Cloud Plan Output\n \\`\\`\\`\n Plan: ${{ steps.plan-output.outputs.add }} to add, ${{ steps.plan-output.outputs.change }} to change, ${{ steps.plan-output.outputs.destroy }} to destroy.\n \\`\\`\\`\n [Terraform Cloud Plan](${{ steps.plan-run.outputs.run_link }})\n `;\n // 3. Delete previous comment so PR timeline makes sense\n if (botComment) {\n github.rest.issues.deleteComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n });\n }\n github.rest.issues.createComment({\n issue_number: context.issue.number,\n owner: context.repo.owner,\n repo: context.repo.repo,\n body: output\n });\n')),Object(a.b)("p",null,"When a Pull Request is created, the GitHub Actions workflow will run the Terraform plan and post the output in the PR comments. So you can ",Object(a.b)("strong",{parentName:"p"},"review the changes")," before merging the PR."),Object(a.b)("p",null,"Here is an example of a GitHub Actions workflow (",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/evoxmusic/qovery-gitops/blob/main/.github/workflows/terraform-plan.yml"}),"GitHub Link"),") when the PR is merged:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-yaml",metastring:'title=".github/workflows/terraform-apply.yml"',title:'".github/workflows/terraform-apply.yml"'}),'name: "Terraform Apply"\n\non:\n push:\n branches:\n - main\n\nenv:\n TF_CLOUD_ORGANIZATION: "YOUR-ORGANIZATION-HERE"\n TF_API_TOKEN: "${{ secrets.TF_API_TOKEN }}"\n TF_WORKSPACE: "YOUR-WORKSPACE-HERE"\n CONFIG_DIRECTORY: "./"\n\njobs:\n terraform:\n name: "Terraform Apply"\n runs-on: ubuntu-latest\n permissions:\n contents: read\n steps:\n - name: Checkout\n uses: actions/checkout@v3\n\n - name: Upload Configuration\n uses: hashicorp/tfc-workflows-github/actions/upload-configuration@v1.0.0\n id: apply-upload\n with:\n workspace: ${{ env.TF_WORKSPACE }}\n directory: ${{ env.CONFIG_DIRECTORY }}\n\n - name: Create Apply Run\n uses: hashicorp/tfc-workflows-github/actions/create-run@v1.0.0\n id: apply-run\n with:\n workspace: ${{ env.TF_WORKSPACE }}\n configuration_version: ${{ steps.apply-upload.outputs.configuration_version_id }}\n\n - name: Apply\n uses: hashicorp/tfc-workflows-github/actions/apply-run@v1.0.0\n if: fromJSON(steps.apply-run.outputs.payload).data.attributes.actions.IsConfirmable\n id: apply\n with:\n run: ${{ steps.apply-run.outputs.run_id }}\n comment: "Apply Run from GitHub Actions CI ${{ github.sha }}"\n')),Object(a.b)("p",null,"When the PR is merged on the main branch, the GitHub Actions workflow will apply the Terraform configuration."),Object(a.b)("h3",{id:"step-5-check-the-qovery-console-to-see-the-resources-created"},"Step 5: Check the Qovery console to see the resources created"),Object(a.b)("p",null,"After the GitHub Actions workflow is completed, you can check the Qovery console to see the resources created."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/resources-created-with-terraform.jpg",alt:"Qovery resources created via Terraform in a GitOps way"})),Object(a.b)("p",null,"As you can see, you can manage your infrastructure and applications using Git repositories as the source of truth with Qovery and Terraform."),Object(a.b)("h2",{id:"frequently-asked-questions-faq"},"Frequently Asked Questions (FAQ)"),Object(a.b)("h3",{id:"how-to-enforce-gitops"},"How to enforce GitOps?"),Object(a.b)("p",null,"Here are the two things we recommend to enforce GitOps with Qovery:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/members-rbac/"}),"Restrict permissions")," of your users to read-only in Qovery. So only the API Qovery Token used by Terraform will be able to create, update, or delete resources. "),Object(a.b)("li",{parentName:"ol"},"Turn off the ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"application auto-deployment")," in Qovery. If you have linked apps via Git with Qovery, you can turn off the auto-deployment.")),Object(a.b)("p",null,"This way, all the changes will be done via the Terraform configuration."),Object(a.b)("h3",{id:"how-to-gitopsify-an-existing-qovery-configuration"},'How to "GitOpsify" an existing Qovery configuration?'),Object(a.b)("p",null,"To make your existing configuration GitOps compatible, you can follow these steps:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Export your existing Qovery configuration with the ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/environment/#terraform-exporter"}),"Terraform exporter"),"."),Object(a.b)("li",{parentName:"ol"},"Edit your exported Terraform configuration."),Object(a.b)("li",{parentName:"ol"},"Test the Terraform configuration locally."),Object(a.b)("li",{parentName:"ol"},"Push the Terraform configuration to a Git repository.")),Object(a.b)("h3",{id:"how-to-see-configuration-drifts"},"How to see configuration drifts?"),Object(a.b)("p",null,"Terraform helps to detect drifts between the desired state and the actual state. When you will create a Pull Request, the GitHub Actions workflow will run the Terraform plan and post the output in the PR comments. So you can review the changes before merging the PR. "),Object(a.b)("p",null,"You can also use the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform plan")," locally command to see the changes that will be applied."),Object(a.b)("h3",{id:"how-to-debug"},"How to debug?"),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Terraform logs"),":\nLet's say you have a problem with the Terraform configuration. You can debug it by checking the Terraform logs in the GitHub Actions workflow. You can also use the Terraform CLI to debug the configuration locally."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Application logs"),":\nIf the problem is not in the Terraform configuration, you can check the Qovery web console to see the resources created and the associated ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/"}),"logs"),"."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"CI/CD logs"),":\nYou can check the GitHub Actions logs to see the Terraform plan and apply outputs."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Qovery logs"),":\nYou can check the Qovery ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/audit-logs/"}),"Audit Logs")," to see the changes made by the Terraform configuration."),Object(a.b)("h3",{id:"how-to-manage-the-terraform-state"},"How to manage the Terraform state?"),Object(a.b)("p",null,"Like in the example above, we recommend using a remote Terraform backend to store the state. This way, you can share the state between your team members and have a history of the changes. You can use the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.hashicorp.com/cloud"}),"Hashicorp Cloud Platform")," or any other Terraform backend you want."),Object(a.b)("h3",{id:"how-to-connect-to-get-terraform-cloud-state"},"How to connect to get Terraform Cloud state?"),Object(a.b)("p",null,"Create a ",Object(a.b)("inlineCode",{parentName:"p"},"backend.tf")," file in your Terraform configuration with the following content:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-hcl",metastring:'title="backend.tf"',title:'"backend.tf"'}),'terraform {\n backend "remote" {\n hostname = "app.terraform.io"\n organization = "Qovery"\n workspaces {\n name = "qovery-gitops"\n }\n }\n}\n')),Object(a.b)("p",null,"Refer to ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://support.hashicorp.com/hc/en-us/articles/360001151948-Migrate-Workspace-State-Using-Terraform-State-Push-Pull"}),"this documentation")),Object(a.b)("h3",{id:"how-to-integrate-tests"},"How to integrate tests?"),Object(a.b)("p",null,"You can use the Qovery API to get the resources URLs and integrate them in your CI/CD. For example, you can get the URL of the application and use it in your tests. Look at this guide on ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/build-e2e-testing-ephemeral-environments/"}),"how to run E2E tests with Qovery and GitHub Actions"),"."),Object(a.b)("h2",{id:"conclusion"},"Conclusion"),Object(a.b)("p",null,"In this tutorial, you learned how to do GitOps with Qovery and the Qovery Terraform provider. You defined all the Qovery resources in a Terraform configuration, tested it locally, pushed it to a GitHub repository, used GitHub Actions to review and apply the Terraform configuration, and checked the Qovery console to see the resources created."),Object(a.b)("p",null,"If you have any questions or need help, feel free to ask in the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Qovery Community Forum"),"."))}m.isMDXComponent=!0},447: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 c=o.a.createContext({}),p=function(e){var t=o.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 o.a.createElement(c.Provider,{value:t},e.children)},m={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,c=s(e,["components","mdxType","originalType","parentName"]),u=p(n),d=r,b=u["".concat(i,".").concat(d)]||u[d]||m[d]||a;return n?o.a.createElement(b,l({ref:t},c,{components:n})):o.a.createElement(b,l({ref:t},c))}));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]=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:r,i[1]=l;for(var c=2;c1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,c=void 0===s?n:o(s,n);c>l;)t[l++]=e;return t}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},454:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),l=n(458),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),m=Object(o.useRef)(!1),d=c.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(p),function(){d&&t&&t.disconnect()}}),[p,d,u]),p&&u?a.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(p),m.current=!0)},innerRef:function(e){var n,r;d&&e&&u&&(n=e,r=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(),r())}))}))).observe(n))},to:p})):a.a.createElement("a",Object(r.a)({},e,{href:p}))}},457:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(454),i=n(447),l=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,s=e.rightIcon,c=e.size,p=e.target,u=e.to,m=l()("jump-to","jump-to--"+c,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-"+(s||"chevron-right")+" arrow"}))));return p?o.a.createElement("a",{href:u,target:p,className:m},d):o.a.createElement(a.a,{to:u,className:m},d)}},458: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 dfcfd2f3.236e52c4.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[263],{415: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 p})),n.d(t,"default",(function(){return m}));var r=n(1),o=n(9),a=(n(0),n(451)),i=n(450),l=n(455),s=(n(459),{last_modified_on:"2024-07-14",$schema:"/.meta/.schemas/guides.json",title:"GitOps with Qovery",description:"How to do GitOps with Qovery, GitHub and Terraform",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:"GitOps with Qovery",description:"How to do GitOps with Qovery, GitHub and Terraform",permalink:"/guides/tutorial/gitops-with-qovery",readingTime:"16 min read",source:"@site/guides/tutorial/gitops-with-qovery.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"GitOps 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:"Grafana setup with Qovery",permalink:"/guides/tutorial/grafana-install"}},p=[{value:"Resources",id:"resources",children:[]},{value:"Terraform vs. YAML",id:"terraform-vs-yaml",children:[]},{value:"Step-by-step tutorial",id:"step-by-step-tutorial",children:[{value:"Step 1: Define the Terraform configuration",id:"step-1-define-the-terraform-configuration",children:[]},{value:"Step 2: Test the Terraform configuration",id:"step-2-test-the-terraform-configuration",children:[]},{value:"Step 3: Push the Terraform configuration to a GitHub repository",id:"step-3-push-the-terraform-configuration-to-a-github-repository",children:[]},{value:"Step 4: Use GitHub Actions to review and apply the Terraform configuration",id:"step-4-use-github-actions-to-review-and-apply-the-terraform-configuration",children:[]},{value:"Step 5: Check the Qovery console to see the resources created",id:"step-5-check-the-qovery-console-to-see-the-resources-created",children:[]}]},{value:"Frequently Asked Questions (FAQ)",id:"frequently-asked-questions-faq",children:[{value:"How to enforce GitOps?",id:"how-to-enforce-gitops",children:[]},{value:"How to "GitOpsify" an existing Qovery configuration?",id:"how-to-gitopsify-an-existing-qovery-configuration",children:[]},{value:"How to see configuration drifts?",id:"how-to-see-configuration-drifts",children:[]},{value:"How to debug?",id:"how-to-debug",children:[]},{value:"How to manage the Terraform state?",id:"how-to-manage-the-terraform-state",children:[]},{value:"How to connect to get Terraform Cloud state?",id:"how-to-connect-to-get-terraform-cloud-state",children:[]},{value:"How to integrate tests?",id:"how-to-integrate-tests",children:[]}]},{value:"Conclusion",id:"conclusion",children:[]}],u={rightToc:p};function m(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,"GitOps is a way to do Continuous Deployment (CD) with Git. It is a practice that allows you to manage your infrastructure and applications using Git repositories as the source of truth. In this tutorial, you will learn how to do GitOps with Qovery and the Qovery Terraform provider."),Object(a.b)("p",null,"Watch this short video to see the final result:"),Object(a.b)("div",{class:"video-container"},Object(a.b)("p",{align:"center"},Object(a.b)("iframe",{src:"https://www.loom.com/embed/f2b82cd32de8474fae7e8cba2d78dd29",width:"100%",height:"100%",frameborder:"0",webkitallowfullscreen:!0,mozallowfullscreen:!0,allowfullscreen:!0}))),Object(a.b)(l.a,{mdxType:"Assumptions"},Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"A ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://console.qovery.com/signup"}),"Qovery account")),Object(a.b)("li",{parentName:"ul"},"General knowledge of Terraform"))),Object(a.b)("p",null,"For our example we will do the following with Terraform:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Define all the Qovery resources in a Terraform configuration"),Object(a.b)("li",{parentName:"ol"},"Test it locally"),Object(a.b)("li",{parentName:"ol"},"Push the Terraform configuration to a GitHub repository"),Object(a.b)("li",{parentName:"ol"},"Use GitHub Actions (CI/CD) to review and apply the Terraform configuration"),Object(a.b)("li",{parentName:"ol"},"Check the Qovery console to see the resources created")),Object(a.b)("p",null,"So let's get started!"),Object(a.b)("h2",{id:"resources"},"Resources"),Object(a.b)("p",null,"Here are some resources you might need:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://console.qovery.com"}),"Qovery web console")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli"}),"Terraform CLI")),Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://registry.terraform.io/providers/Qovery/qovery/latest/docs"}),"Qovery Terraform Provider"))),Object(a.b)("h2",{id:"terraform-vs-yaml"},"Terraform vs. YAML"),Object(a.b)("p",null,"Just before we start, let's talk about why we use Terraform instead of YAML to manage the infrastructure in a GitOps way. Qovery provides an ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://registry.terraform.io/providers/Qovery/qovery/latest/docs"}),"official Terraform provider")," to manage your infrastructure. We did the choice to use Terraform instead of YAML for the following reasons:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},"Terraform is a well-known tool in the DevOps community"),Object(a.b)("li",{parentName:"ul"},"Terraform gets the state of the infrastructure, which is useful to know what is already created"),Object(a.b)("li",{parentName:"ul"},"Terraform helps to detect drifts between the desired state and the actual state")),Object(a.b)("p",null,"If you are not familiar with Terraform, you can learn more about it on the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.terraform.io/"}),"official website"),"."),Object(a.b)("h2",{id:"step-by-step-tutorial"},"Step-by-step tutorial"),Object(a.b)("p",null,"For this tutorial, we will create a simple Qovery application with a PostgreSQL database. This is just for demo purposes. You can adapt the Terraform configuration to your needs.\nThen We will use Terraform to define the resources and GitHub Actions to apply the Terraform configuration."),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,"To enforce GitOps with Qovery, you can limit the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/members-rbac/"}),"permissions")," of your users to read-only in the Qovery console. This way, all the changes will be done via the Terraform configuration.")),Object(a.b)("h3",{id:"step-1-define-the-terraform-configuration"},"Step 1: Define the Terraform configuration"),Object(a.b)("p",null,"Create a new directory and add a ",Object(a.b)("inlineCode",{parentName:"p"},"variables.tf")," and a ",Object(a.b)("inlineCode",{parentName:"p"},"main.tf")," file with the following content:"),Object(a.b)(i.a,{type:"info",mdxType:"Alert"},Object(a.b)("p",null,Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment/#terraform-exporter"}),"Export your Terraform configuration")," if you have already created your resources with the Qovery web console. ")),Object(a.b)("p",null,Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/evoxmusic/qovery-gitops/blob/main/variables.tf"}),"Read this example on GitHub")),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-hcl",metastring:'title="variables.tf"',title:'"variables.tf"'}),'variable "qovery_token" {\n description = "Qovery API token"\n type = string\n}\n\nvariable "qovery_organization_id" {\n description = "Qovery Organization ID"\n type = string\n}\n\nvariable "qovery_cluster_id" {\n description = "My Qovery Test Cluster ID"\n type = string\n}\n')),Object(a.b)("p",null,Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/evoxmusic/qovery-gitops/blob/main/main.tf"}),"Read this example on GitHub")),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-hcl",metastring:'title="main.tf"',title:'"main.tf"'}),'terraform {\n required_providers {\n qovery = {\n source = "qovery/qovery"\n }\n }\n}\n\nprovider "qovery" {\n token = var.qovery_access_token\n}\n\nresource "qovery_project" "my_project" {\n organization_id = var.qovery_organization_id\n name = "My TF Project"\n}\n\nresource "qovery_environment" "production" {\n project_id = qovery_project.my_project.id\n name = "production"\n mode = "PRODUCTION"\n cluster_id = var.qovery_cluster_id\n}\n\nresource "qovery_database" "my_database" {\n environment_id = qovery_environment.production.id\n name = "My DB"\n type = "POSTGRESQL"\n version = "16"\n mode = "CONTAINER"\n storage = 10\n accessibility = "PRIVATE"\n}\n\nresource "qovery_application" "my_backend" {\n environment_id = qovery_environment.production.id\n name = "My Backend"\n cpu = 250\n memory = 128\n git_repository = {\n url = "https://github.com/evoxmusic/ShortMe-URL-Shortener.git"\n branch = "main"\n root_path = "/"\n }\n build_mode = "DOCKER"\n dockerfile_path = "Dockerfile"\n ports = [\n {\n internal_port = 5555\n external_port = 443\n protocol = "HTTP"\n publicly_accessible = true\n is_default = true\n }\n ]\n healthchecks = {\n readiness_probe = {\n type = {\n http = {\n port = 5555\n scheme = "HTTP"\n path = "/"\n }\n }\n initial_delay_seconds = 30\n period_seconds = 10\n timeout_seconds = 10\n success_threshold = 1\n failure_threshold = 3\n }\n liveness_probe = {\n type = {\n http = {\n port = 5555\n scheme = "HTTP"\n path = "/"\n }\n }\n initial_delay_seconds = 30\n period_seconds = 10\n timeout_seconds = 10\n success_threshold = 1\n failure_threshold = 3\n }\n }\n environment_variables = [\n {\n key = "DATABASE_HOST"\n value = qovery_database.my_database.internal_host\n },\n {\n key = "DATABASE_PORT"\n value = qovery_database.my_database.port\n },\n {\n key = "DATABASE_USERNAME"\n value = qovery_database.my_database.login\n },\n {\n key = "DATABASE_NAME"\n value = "postgres"\n },\n ]\n secrets = [\n {\n key = "DATABASE_PASSWORD"\n value = qovery_database.my_database.password\n }\n ]\n}\n\nresource "qovery_deployment" "my_deployment" {\n environment_id = qovery_environment.production.id\n desired_state = "RUNNING"\n version = "a0282bb4-f5bb-44ed-882d-e067f92d105e"\n\n depends_on = [\n qovery_application.my_backend,\n qovery_database.my_database,\n qovery_environment.production,\n ]\n}\n')),Object(a.b)("p",null,"My arborescence looks like this:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-shell"}),"$ ls -lh\n\nPermissions Size User Date Modified Name\n.rw-r--r-- 2.8k xxx 11 Jul 10:28 main.tf\n.rw-r--r-- 297 xxx 10 Jul 17:24 variables.tf\n")),Object(a.b)("h3",{id:"step-2-test-the-terraform-configuration"},"Step 2: Test the Terraform configuration"),Object(a.b)("h4",{id:"generate-a-qovery-token"},"Generate a Qovery token"),Object(a.b)("p",null,"To test your Terraform configuration, you first need to generate a Qovery token. You can do this by following the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/api-token/"}),"official documentation"),"."),Object(a.b)("h4",{id:"test-terraform-configuration-locally"},"Test Terraform configuration locally"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Download and install ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://developer.hashicorp.com/terraform/install"}),"Terraform CLI")),Object(a.b)("li",{parentName:"ol"},"Set environment variables ",Object(a.b)("ol",{parentName:"li"},Object(a.b)("li",{parentName:"ol"},"Qovery API Token: ",Object(a.b)("inlineCode",{parentName:"li"},"export TF_VAR_qovery_token=XXX")),Object(a.b)("li",{parentName:"ol"},"Qovery Organization ID: ",Object(a.b)("inlineCode",{parentName:"li"},"export TF_VAR_qovery_organization_id=XXX")),Object(a.b)("li",{parentName:"ol"},"Qovery Cluster ID: ",Object(a.b)("inlineCode",{parentName:"li"},"export TF_VAR_qovery_cluster_id=XXX")))),Object(a.b)("li",{parentName:"ol"},"Init Terraform modules: ",Object(a.b)("inlineCode",{parentName:"li"},"terraform init")),Object(a.b)("li",{parentName:"ol"},"Plan the Terraform configuration: ",Object(a.b)("inlineCode",{parentName:"li"},"terraform plan")),Object(a.b)("li",{parentName:"ol"},"Apply the Terraform configuration: ",Object(a.b)("inlineCode",{parentName:"li"},"terraform apply -auto-approve"))),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Test Terraform locally"',title:'"Test',Terraform:!0,'locally"':!0}),"$ export TF_VAR_qovery_token=XXX TF_VAR_qovery_token=XXX TF_VAR_qovery_cluster_id=XXX\n\n$ terraform init && terraform apply -auto-approve\n")),Object(a.b)("p",null,"The output should show the resources created."),Object(a.b)("details",null,Object(a.b)("summary",null,"Example output"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-shell",metastring:'title="Terraform output"',title:'"Terraform','output"':!0}),'Terraform used the selected providers to generate the following execution plan. Resource actions are\nindicated with the following symbols:\n + create\n\nTerraform will perform the following actions:\n\n # qovery_application.my_backend will be created\n + resource "qovery_application" "my_backend" {\n + advanced_settings_json = (known after apply)\n + arguments = (known after apply)\n + auto_deploy = (known after apply)\n + auto_preview = false\n + build_mode = "DOCKER"\n + built_in_environment_variables = (known after apply)\n + cpu = 250\n + deployment_stage_id = (known after apply)\n + dockerfile_path = "Dockerfile"\n + environment_id = (known after apply)\n + environment_variables = [\n + {\n + id = (known after apply)\n + key = "DATABASE_HOST"\n + value = (known after apply)\n },\n + {\n + id = (known after apply)\n + key = "DATABASE_NAME"\n + value = "postgres"\n },\n + {\n + id = (known after apply)\n + key = "DATABASE_PORT"\n + value = (known after apply)\n },\n + {\n + id = (known after apply)\n + key = "DATABASE_USERNAME"\n + value = (known after apply)\n },\n ]\n + external_host = (known after apply)\n + git_repository = {\n + branch = "main"\n + root_path = "/"\n + url = "https://github.com/evoxmusic/ShortMe-URL-Shortener.git"\n }\n + healthchecks = {\n + liveness_probe = {\n + failure_threshold = 3\n + initial_delay_seconds = 30\n + period_seconds = 10\n + success_threshold = 1\n + timeout_seconds = 10\n + type = {\n + http = {\n + path = "/"\n + port = 5555\n + scheme = "HTTP"\n }\n }\n }\n + readiness_probe = {\n + failure_threshold = 3\n + initial_delay_seconds = 30\n + period_seconds = 10\n + success_threshold = 1\n + timeout_seconds = 10\n + type = {\n + http = {\n + path = "/"\n + port = 5555\n + scheme = "HTTP"\n }\n }\n }\n }\n + id = (known after apply)\n + internal_host = (known after apply)\n + max_running_instances = 1\n + memory = 128\n + min_running_instances = 1\n + name = "My Backend"\n + ports = [\n + {\n + external_port = 443\n + id = (known after apply)\n + internal_port = 5555\n + is_default = true\n + name = (known after apply)\n + protocol = "HTTP"\n + publicly_accessible = true\n },\n ]\n + secrets = (sensitive value)\n }\n\n # qovery_database.my_database will be created\n + resource "qovery_database" "my_database" {\n + accessibility = "PRIVATE"\n + cpu = 250\n + deployment_stage_id = (known after apply)\n + environment_id = (known after apply)\n + external_host = (known after apply)\n + id = (known after apply)\n + instance_type = (known after apply)\n + internal_host = (known after apply)\n + login = (known after apply)\n + memory = 256\n + mode = "CONTAINER"\n + name = "My DB"\n + password = (known after apply)\n + port = (known after apply)\n + storage = 10\n + type = "POSTGRESQL"\n + version = "16"\n }\n\n # qovery_deployment.my_deployment will be created\n + resource "qovery_deployment" "my_deployment" {\n + desired_state = "RUNNING"\n + environment_id = (known after apply)\n + id = (known after apply)\n + version = "a0282bb4-f5bb-44ed-882d-e067f92d106e"\n }\n\n # qovery_environment.production will be created\n + resource "qovery_environment" "production" {\n + built_in_environment_variables = (known after apply)\n + cluster_id = "809f9644-b3e4-400b-97fc-e2173d46a00e"\n + id = (known after apply)\n + mode = "PRODUCTION"\n + name = "production"\n + project_id = (known after apply)\n }\n\n # qovery_project.my_project will be created\n + resource "qovery_project" "my_project" {\n + built_in_environment_variables = (known after apply)\n + description = (known after apply)\n + id = (known after apply)\n + name = "My TF Project"\n + organization_id = "141c07c8-0dd9-4623-983b-3fdd61867255"\n }\n\nPlan: 5 to add, 0 to change, 0 to destroy.\nqovery_project.my_project: Creating...\nqovery_project.my_project: Creation complete after 1s [id=66ad165a-f7f8-4840-8519-8db11ae7d127]\nqovery_environment.production: Creating...\nqovery_environment.production: Creation complete after 1s [id=a51a7e66-af37-425a-92a7-c07b9f1752fc]\nqovery_database.my_database: Creating...\nqovery_database.my_database: Creation complete after 2s [id=454b5baa-1465-4383-a822-32f1511222a0]\nqovery_application.my_backend: Creating...\nqovery_application.my_backend: Creation complete after 3s [id=a4ff2488-ad6a-4218-9e52-68aa3ebdd059]\nqovery_deployment.my_deployment: Creating...\nqovery_deployment.my_deployment: Still creating... [10s elapsed]\nqovery_deployment.my_deployment: Still creating... [20s elapsed]\nqovery_deployment.my_deployment: Still creating... [30s elapsed]\nqovery_deployment.my_deployment: Still creating... [40s elapsed]\nqovery_deployment.my_deployment: Still creating... [50s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m0s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m10s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m20s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m30s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m40s elapsed]\nqovery_deployment.my_deployment: Still creating... [1m50s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m0s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m10s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m20s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m30s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m40s elapsed]\nqovery_deployment.my_deployment: Still creating... [2m50s elapsed]\nqovery_deployment.my_deployment: Still creating... [3m0s elapsed]\nqovery_deployment.my_deployment: Still creating... [3m10s elapsed]\nqovery_deployment.my_deployment: Still creating... [3m20s elapsed]\nqovery_deployment.my_deployment: Creation complete after 3m24s [id=84435485-eb50-4051-b91f-61f99985edf2]\n\nApply complete! Resources: 5 added, 0 changed, 0 destroyed.\n'))),Object(a.b)("p",null,"If you edit resources in the Terraform configuration, you can re-apply the changes with ",Object(a.b)("inlineCode",{parentName:"p"},"terraform apply -auto-approve"),". Note that for service resources, when you change the configuration, you need to redeploy them by updating the ",Object(a.b)("inlineCode",{parentName:"p"},"qovery_deployment.version")," UUID."),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Once you have tested your Terraform configuration locally, you must clean up the resources with ",Object(a.b)("inlineCode",{parentName:"p"},"terraform destroy -auto-approve")," since we will use our CI/CD tool to apply the Terraform configuration and a remote Terraform backend to store the state.")),Object(a.b)("h3",{id:"step-3-push-the-terraform-configuration-to-a-github-repository"},"Step 3: Push the Terraform configuration to a GitHub repository"),Object(a.b)("p",null,"Since we have tested the Terraform configuration locally, we can now push it to your Git repository. In my case, I will use GitHub."),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Create a Git repository"),Object(a.b)("li",{parentName:"ol"},"Commit and push the Terraform configuration to the repository")),Object(a.b)(i.a,{type:"warning",mdxType:"Alert"},Object(a.b)("p",null,"Make sure to add the ",Object(a.b)("inlineCode",{parentName:"p"},".terraform")," directory and other generated terraform metafiles to your ",Object(a.b)("inlineCode",{parentName:"p"},".gitignore")," file.")),Object(a.b)("p",null,"Here is a .gitignore you can use:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-gitignore",metastring:'title=".gitignore"',title:'".gitignore"'}),"# Local .terraform directories\n**/.terraform/*\n\n# .tfstate files\n*.tfstate\n*.tfstate.*\n\n# Crash log files\ncrash.log\ncrash.*.log\n\n# Exclude all .tfvars files, which are likely to contain sensitive data, such as\n# password, private keys, and other secrets. These should not be part of version \n# control as they are data points which are potentially sensitive and subject \n# to change depending on the environment.\n*.tfvars\n*.tfvars.json\n\n# Ignore override files as they are usually used to override resources locally and so\n# are not checked in\noverride.tf\noverride.tf.json\n*_override.tf\n*_override.tf.json\n\n# Include override files you do wish to add to version control using negated pattern\n# !example_override.tf\n\n# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan\n# example: *tfplan*\n\n# Ignore CLI configuration files\n.terraformrc\nterraform.rc\n")),Object(a.b)("h3",{id:"step-4-use-github-actions-to-review-and-apply-the-terraform-configuration"},"Step 4: Use GitHub Actions to review and apply the Terraform configuration"),Object(a.b)("p",null,"In my case, I will use:"),Object(a.b)("ul",null,Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://github.com/features/actions"}),"GitHub Actions")," as a CI tool to review and apply the Terraform."),Object(a.b)("li",{parentName:"ul"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"https://www.hashicorp.com/cloud"}),"Hashicorp Cloud Platform")," as a Terraform backend state. ")),Object(a.b)("p",null,"Note that you can use any CI/CD tool and Terraform backend you want."),Object(a.b)("p",null,Object(a.b)("em",{parentName:"p"},"This section is inspired by the official ",Object(a.b)("a",Object(r.a)({parentName:"em"},{href:"https://developer.hashicorp.com/terraform/tutorials/automation/github-actions"}),"Terraform GitHub Actions documentation"),".")),Object(a.b)("p",null,"Here is an example of a GitHub Actions workflow (",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/evoxmusic/qovery-gitops/blob/main/.github/workflows/terraform-plan.yml"}),"GitHub Link"),") when a Pull Request is created:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-yaml",metastring:'title=".github/workflows/terraform-plan.yml"',title:'".github/workflows/terraform-plan.yml"'}),'name: "Terraform Plan"\n\non:\n pull_request:\n\nenv:\n TF_CLOUD_ORGANIZATION: "YOUR-ORGANIZATION-HERE"\n TF_API_TOKEN: "${{ secrets.TF_API_TOKEN }}"\n TF_WORKSPACE: "YOUR-WORKSPACE-HERE"\n CONFIG_DIRECTORY: "./"\n\njobs:\n terraform:\n name: "Terraform Plan"\n runs-on: ubuntu-latest\n permissions:\n contents: read\n pull-requests: write\n steps:\n - name: Checkout\n uses: actions/checkout@v3\n\n - name: Upload Configuration\n uses: hashicorp/tfc-workflows-github/actions/upload-configuration@v1.0.0\n id: plan-upload\n with:\n workspace: ${{ env.TF_WORKSPACE }}\n directory: ${{ env.CONFIG_DIRECTORY }}\n speculative: true\n\n - name: Create Plan Run\n uses: hashicorp/tfc-workflows-github/actions/create-run@v1.0.0\n id: plan-run\n with:\n workspace: ${{ env.TF_WORKSPACE }}\n configuration_version: ${{ steps.plan-upload.outputs.configuration_version_id }}\n plan_only: true\n\n - name: Get Plan Output\n uses: hashicorp/tfc-workflows-github/actions/plan-output@v1.0.0\n id: plan-output\n with:\n plan: ${{ fromJSON(steps.plan-run.outputs.payload).data.relationships.plan.data.id }}\n\n - name: Update PR\n uses: actions/github-script@v6\n id: plan-comment\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n // 1. Retrieve existing bot comments for the PR\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n const botComment = comments.find(comment => {\n return comment.user.type === \'Bot\' && comment.body.includes(\'Terraform Cloud Plan Output\')\n });\n const output = `#### Terraform Cloud Plan Output\n \\`\\`\\`\n Plan: ${{ steps.plan-output.outputs.add }} to add, ${{ steps.plan-output.outputs.change }} to change, ${{ steps.plan-output.outputs.destroy }} to destroy.\n \\`\\`\\`\n [Terraform Cloud Plan](${{ steps.plan-run.outputs.run_link }})\n `;\n // 3. Delete previous comment so PR timeline makes sense\n if (botComment) {\n github.rest.issues.deleteComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n });\n }\n github.rest.issues.createComment({\n issue_number: context.issue.number,\n owner: context.repo.owner,\n repo: context.repo.repo,\n body: output\n });\n')),Object(a.b)("p",null,"When a Pull Request is created, the GitHub Actions workflow will run the Terraform plan and post the output in the PR comments. So you can ",Object(a.b)("strong",{parentName:"p"},"review the changes")," before merging the PR."),Object(a.b)("p",null,"Here is an example of a GitHub Actions workflow (",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://github.com/evoxmusic/qovery-gitops/blob/main/.github/workflows/terraform-plan.yml"}),"GitHub Link"),") when the PR is merged:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-yaml",metastring:'title=".github/workflows/terraform-apply.yml"',title:'".github/workflows/terraform-apply.yml"'}),'name: "Terraform Apply"\n\non:\n push:\n branches:\n - main\n\nenv:\n TF_CLOUD_ORGANIZATION: "YOUR-ORGANIZATION-HERE"\n TF_API_TOKEN: "${{ secrets.TF_API_TOKEN }}"\n TF_WORKSPACE: "YOUR-WORKSPACE-HERE"\n CONFIG_DIRECTORY: "./"\n\njobs:\n terraform:\n name: "Terraform Apply"\n runs-on: ubuntu-latest\n permissions:\n contents: read\n steps:\n - name: Checkout\n uses: actions/checkout@v3\n\n - name: Upload Configuration\n uses: hashicorp/tfc-workflows-github/actions/upload-configuration@v1.0.0\n id: apply-upload\n with:\n workspace: ${{ env.TF_WORKSPACE }}\n directory: ${{ env.CONFIG_DIRECTORY }}\n\n - name: Create Apply Run\n uses: hashicorp/tfc-workflows-github/actions/create-run@v1.0.0\n id: apply-run\n with:\n workspace: ${{ env.TF_WORKSPACE }}\n configuration_version: ${{ steps.apply-upload.outputs.configuration_version_id }}\n\n - name: Apply\n uses: hashicorp/tfc-workflows-github/actions/apply-run@v1.0.0\n if: fromJSON(steps.apply-run.outputs.payload).data.attributes.actions.IsConfirmable\n id: apply\n with:\n run: ${{ steps.apply-run.outputs.run_id }}\n comment: "Apply Run from GitHub Actions CI ${{ github.sha }}"\n')),Object(a.b)("p",null,"When the PR is merged on the main branch, the GitHub Actions workflow will apply the Terraform configuration."),Object(a.b)("h3",{id:"step-5-check-the-qovery-console-to-see-the-resources-created"},"Step 5: Check the Qovery console to see the resources created"),Object(a.b)("p",null,"After the GitHub Actions workflow is completed, you can check the Qovery console to see the resources created."),Object(a.b)("p",{align:"center"},Object(a.b)("img",{src:"/img/resources-created-with-terraform.jpg",alt:"Qovery resources created via Terraform in a GitOps way"})),Object(a.b)("p",null,"As you can see, you can manage your infrastructure and applications using Git repositories as the source of truth with Qovery and Terraform."),Object(a.b)("h2",{id:"frequently-asked-questions-faq"},"Frequently Asked Questions (FAQ)"),Object(a.b)("h3",{id:"how-to-enforce-gitops"},"How to enforce GitOps?"),Object(a.b)("p",null,"Here are the two things we recommend to enforce GitOps with Qovery:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/organization/members-rbac/"}),"Restrict permissions")," of your users to read-only in Qovery. So only the API Qovery Token used by Terraform will be able to create, update, or delete resources. "),Object(a.b)("li",{parentName:"ol"},"Turn off the ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/deployment/deploying-with-auto-deploy/"}),"application auto-deployment")," in Qovery. If you have linked apps via Git with Qovery, you can turn off the auto-deployment.")),Object(a.b)("p",null,"This way, all the changes will be done via the Terraform configuration."),Object(a.b)("h3",{id:"how-to-gitopsify-an-existing-qovery-configuration"},'How to "GitOpsify" an existing Qovery configuration?'),Object(a.b)("p",null,"To make your existing configuration GitOps compatible, you can follow these steps:"),Object(a.b)("ol",null,Object(a.b)("li",{parentName:"ol"},"Export your existing Qovery configuration with the ",Object(a.b)("a",Object(r.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/environment/#terraform-exporter"}),"Terraform exporter"),"."),Object(a.b)("li",{parentName:"ol"},"Edit your exported Terraform configuration."),Object(a.b)("li",{parentName:"ol"},"Test the Terraform configuration locally."),Object(a.b)("li",{parentName:"ol"},"Push the Terraform configuration to a Git repository.")),Object(a.b)("h3",{id:"how-to-see-configuration-drifts"},"How to see configuration drifts?"),Object(a.b)("p",null,"Terraform helps to detect drifts between the desired state and the actual state. When you will create a Pull Request, the GitHub Actions workflow will run the Terraform plan and post the output in the PR comments. So you can review the changes before merging the PR. "),Object(a.b)("p",null,"You can also use the ",Object(a.b)("inlineCode",{parentName:"p"},"terraform plan")," locally command to see the changes that will be applied."),Object(a.b)("h3",{id:"how-to-debug"},"How to debug?"),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Terraform logs"),":\nLet's say you have a problem with the Terraform configuration. You can debug it by checking the Terraform logs in the GitHub Actions workflow. You can also use the Terraform CLI to debug the configuration locally."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Application logs"),":\nIf the problem is not in the Terraform configuration, you can check the Qovery web console to see the resources created and the associated ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/deployment/logs/"}),"logs"),"."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"CI/CD logs"),":\nYou can check the GitHub Actions logs to see the Terraform plan and apply outputs."),Object(a.b)("p",null,Object(a.b)("strong",{parentName:"p"},"Qovery logs"),":\nYou can check the Qovery ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/audit-logs/"}),"Audit Logs")," to see the changes made by the Terraform configuration."),Object(a.b)("h3",{id:"how-to-manage-the-terraform-state"},"How to manage the Terraform state?"),Object(a.b)("p",null,"Like in the example above, we recommend using a remote Terraform backend to store the state. This way, you can share the state between your team members and have a history of the changes. You can use the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://www.hashicorp.com/cloud"}),"Hashicorp Cloud Platform")," or any other Terraform backend you want."),Object(a.b)("h3",{id:"how-to-connect-to-get-terraform-cloud-state"},"How to connect to get Terraform Cloud state?"),Object(a.b)("p",null,"Create a ",Object(a.b)("inlineCode",{parentName:"p"},"backend.tf")," file in your Terraform configuration with the following content:"),Object(a.b)("pre",null,Object(a.b)("code",Object(r.a)({parentName:"pre"},{className:"language-hcl",metastring:'title="backend.tf"',title:'"backend.tf"'}),'terraform {\n backend "remote" {\n hostname = "app.terraform.io"\n organization = "Qovery"\n workspaces {\n name = "qovery-gitops"\n }\n }\n}\n')),Object(a.b)("p",null,"Refer to ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://support.hashicorp.com/hc/en-us/articles/360001151948-Migrate-Workspace-State-Using-Terraform-State-Push-Pull"}),"this documentation")),Object(a.b)("h3",{id:"how-to-integrate-tests"},"How to integrate tests?"),Object(a.b)("p",null,"You can use the Qovery API to get the resources URLs and integrate them in your CI/CD. For example, you can get the URL of the application and use it in your tests. Look at this guide on ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"/guides/tutorial/build-e2e-testing-ephemeral-environments/"}),"how to run E2E tests with Qovery and GitHub Actions"),"."),Object(a.b)("h2",{id:"conclusion"},"Conclusion"),Object(a.b)("p",null,"In this tutorial, you learned how to do GitOps with Qovery and the Qovery Terraform provider. You defined all the Qovery resources in a Terraform configuration, tested it locally, pushed it to a GitHub repository, used GitHub Actions to review and apply the Terraform configuration, and checked the Qovery console to see the resources created."),Object(a.b)("p",null,"If you have any questions or need help, feel free to ask in the ",Object(a.b)("a",Object(r.a)({parentName:"p"},{href:"https://discuss.qovery.com/"}),"Qovery Community Forum"),"."))}m.isMDXComponent=!0},449: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 c=o.a.createContext({}),p=function(e){var t=o.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 o.a.createElement(c.Provider,{value:t},e.children)},m={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,c=s(e,["components","mdxType","originalType","parentName"]),u=p(n),d=r,b=u["".concat(i,".").concat(d)]||u[d]||m[d]||a;return n?o.a.createElement(b,l({ref:t},c,{components:n})):o.a.createElement(b,l({ref:t},c))}));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]=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:r,i[1]=l;for(var c=2;c1?arguments[1]:void 0,n),s=i>2?arguments[2]:void 0,c=void 0===s?n:o(s,n);c>l;)t[l++]=e;return t}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},456:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),l=n(460),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),m=Object(o.useRef)(!1),d=c.a.canUseIntersectionObserver;return Object(o.useEffect)((function(){return!d&&u&&window.docusaurus.prefetch(p),function(){d&&t&&t.disconnect()}}),[p,d,u]),p&&u?a.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){m.current||(window.docusaurus.preload(p),m.current=!0)},innerRef:function(e){var n,r;d&&e&&u&&(n=e,r=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(),r())}))}))).observe(n))},to:p})):a.a.createElement("a",Object(r.a)({},e,{href:p}))}},459:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(456),i=n(449),l=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.className,r=e.badge,i=e.leftIcon,s=e.rightIcon,c=e.size,p=e.target,u=e.to,m=l()("jump-to","jump-to--"+c,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-"+(s||"chevron-right")+" arrow"}))));return p?o.a.createElement("a",{href:u,target:p,className:m},d):o.a.createElement(a.a,{to:u,className:m},d)}},460: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/e06f2af5.8b12fef7.js.LICENSE.txt b/dfcfd2f3.236e52c4.js.LICENSE.txt similarity index 100% rename from e06f2af5.8b12fef7.js.LICENSE.txt rename to dfcfd2f3.236e52c4.js.LICENSE.txt diff --git a/ff2506fd.b1ec280b.js b/dffbf523.8657a2c2.js similarity index 89% rename from ff2506fd.b1ec280b.js rename to dffbf523.8657a2c2.js index 953509f315..a2cbeb24be 100644 --- a/ff2506fd.b1ec280b.js +++ b/dffbf523.8657a2c2.js @@ -1,2 +1,2 @@ -/*! For license information please see ff2506fd.b1ec280b.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[289],{441: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 c})),r.d(t,"default",(function(){return p}));var n=r(1),a=r(9),i=(r(0),r(449)),o=r(448),l={last_modified_on:"2024-01-02",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Kubernetes cluster",description:"Learn how to install Qovery on your own Kubernetes cluster (BYOK)",series_position:4,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: kubernetes"]},u={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery on your Kubernetes cluster",description:"Learn how to install Qovery on your own Kubernetes cluster (BYOK)",permalink:"/guides/installation-guide/guide-kubernetes",readingTime:"1 min read",seriesPosition:4,source:"@site/guides/installation-guide/guide-kubernetes.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: kubernetes",permalink:"/guides/tags/installation-guide-kubernetes"}],title:"Install Qovery on your Kubernetes cluster",truncated:!1,prevItem:{title:"Install Qovery on your Scaleway account",permalink:"/guides/installation-guide/guide-scaleway"},nextItem:{title:"Install Qovery on your Microsoft Azure account",permalink:"/guides/installation-guide/guide-microsoft-azure"}},c=[],s={rightToc:c};function p(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(i.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(i.b)(o.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"Access our new installation guide of Qovery on Kubernetes ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/"}),"here"))))}p.isMDXComponent=!0},447: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 i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=a.a.createContext({}),s=function(e){var t=a.a.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l({},t,{},e)),r},p=function(e){var t=s(e.components);return a.a.createElement(c.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(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,o=e.parentName,c=u(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,y=p["".concat(o,".").concat(d)]||p[d]||f[d]||i;return r?a.a.createElement(y,l({ref:t},c,{components:r})):a.a.createElement(y,l({ref:t},c))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,o=new Array(i);o[0]=d;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l.mdxType="string"==typeof e?e:n,o[1]=l;for(var c=2;c1?arguments[1]:void 0,r),u=o>2?arguments[2]:void 0,c=void 0===u?r:a(u,r);c>l;)t[l++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see dffbf523.8657a2c2.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[264],{416: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 c})),r.d(t,"default",(function(){return p}));var n=r(1),a=r(9),i=(r(0),r(451)),o=r(450),l={last_modified_on:"2024-01-02",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Kubernetes cluster",description:"Learn how to install Qovery on your own Kubernetes cluster (BYOK)",series_position:4,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: kubernetes"]},u={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery on your Kubernetes cluster",description:"Learn how to install Qovery on your own Kubernetes cluster (BYOK)",permalink:"/guides/installation-guide/guide-kubernetes",readingTime:"1 min read",seriesPosition:4,source:"@site/guides/installation-guide/guide-kubernetes.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: kubernetes",permalink:"/guides/tags/installation-guide-kubernetes"}],title:"Install Qovery on your Kubernetes cluster",truncated:!1,prevItem:{title:"Install Qovery on your Scaleway account",permalink:"/guides/installation-guide/guide-scaleway"},nextItem:{title:"Install Qovery on your Microsoft Azure account",permalink:"/guides/installation-guide/guide-microsoft-azure"}},c=[],s={rightToc:c};function p(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(i.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(i.b)(o.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"Access our new installation guide of Qovery on Kubernetes ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/"}),"here"))))}p.isMDXComponent=!0},449: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 i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=a.a.createContext({}),s=function(e){var t=a.a.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l({},t,{},e)),r},p=function(e){var t=s(e.components);return a.a.createElement(c.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(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,o=e.parentName,c=u(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,y=p["".concat(o,".").concat(d)]||p[d]||f[d]||i;return r?a.a.createElement(y,l({ref:t},c,{components:r})):a.a.createElement(y,l({ref:t},c))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,o=new Array(i);o[0]=d;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l.mdxType="string"==typeof e?e:n,o[1]=l;for(var c=2;c1?arguments[1]:void 0,r),u=o>2?arguments[2]:void 0,c=void 0===u?r:a(u,r);c>l;)t[l++]=e;return t}}}]); \ No newline at end of file diff --git a/e1becc8e.2e500b86.js.LICENSE.txt b/dffbf523.8657a2c2.js.LICENSE.txt similarity index 100% rename from e1becc8e.2e500b86.js.LICENSE.txt rename to dffbf523.8657a2c2.js.LICENSE.txt diff --git a/docs/getting-started/basic-concepts/index.html b/docs/getting-started/basic-concepts/index.html index 9be0914439..88194caeab 100644 --- a/docs/getting-started/basic-concepts/index.html +++ b/docs/getting-started/basic-concepts/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

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.

Managed Cluster

A Managed Cluster is a Kubernetes cluster managed by Qovery. It means that Qovery will create the cluster for you and will take care of the cluster lifecycle (creation, upgrade, deletion etc..). Zero maintenance for you.

Self-Managed Cluster

A Self-Managed Cluster is a Kubernetes cluster managed by you. It means that you have to create the cluster yourself and you have to take care of the cluster lifecycle (creation, upgrade, deletion etc..). You can install Qovery on your cluster to let Qovery manage the deployment of your applications on your cluster.

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 (or Ephemeral 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.

Five types 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
  • Helm: it allows you to deploy a helm chart on your cluster. More information about Helm 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 df302e92af..92ae1cff17 100644 --- a/docs/getting-started/deploy-my-app/index.html +++ b/docs/getting-started/deploy-my-app/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

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 abf8b47572..92fdeac9bf 100644 --- a/docs/getting-started/how-qovery-works/index.html +++ b/docs/getting-started/how-qovery-works/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

    How Qovery Works

    Qovery is a service that runs on top of your Kubernetes cluster. It is composed of two main components:

    Control Plane

    The control plane is the brain of Qovery. It is responsible for:

    • Orchestrating the lifecycle of your applications
    • Managing the access and permissions of your team members
    • Providing the API to interact with Qovery

    Remote Agents

    The remote agents are the workers of Qovery. They are responsible for:

    • Deploying your applications
    • Managing the lifecycle of your applications
    • Gathering metrics and logs from your applications

    Curious to know more how Qovery works in detail? Refer to this article

    - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/index.html b/docs/getting-started/index.html index bc23b9706e..11b17f15dc 100644 --- a/docs/getting-started/index.html +++ b/docs/getting-started/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@
    Resources
      - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials/index.html b/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials/index.html index 08c6165660..d6296e176c 100644 --- a/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials/index.html +++ b/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -54,27 +54,27 @@ Follow this documentation to create a new cluster on your organization.

      Next steps

      Now you can use your AWS account to deploy your applications on Qovery. You can also link other Cloud providers to your organization.

      - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/faq/index.html b/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/faq/index.html index b7cb0a1201..b686ba8ee1 100644 --- a/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/faq/index.html +++ b/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/faq/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -54,27 +54,27 @@ 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/getting-started/install-qovery/aws/cluster-managed-by-qovery/index.html b/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/index.html index 5bf31e5d38..56d91ff81a 100644 --- a/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/index.html +++ b/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@
      Resources
        - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure/index.html b/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure/index.html index 3a0d85a11b..c867a520a2 100644 --- a/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure/index.html +++ b/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -57,27 +57,27 @@ 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": "*"
        }
        ]
        }
        - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/index.html b/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/index.html index e869d30bb4..e3ddb88043 100644 --- a/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/index.html +++ b/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

        Quickstart

        Install Qovery on your AWS account in less than 30 minutes. Qovery will create a Kubernetes cluster for you and manage it for you. To install Qovery on an existing Kubernetes cluster, please refer to the dedicated documentation.

        1. Create a Kubernetes cluster

          Now you can create your Kubernetes cluster. Follow this guide to create your Kubernetes cluster.

          Add Cluster

          Note that you can create multiple clusters on the same AWS account with different VPCs. You can also create multiple clusters on different AWS accounts. Qovery will manage them for you.

        2. Attach AWS credentials

          Follow this guide to create your AWS credentials.

          Create Credentials

          Then attach your credentials to your cluster and click on Create. Then, click on Continue.

        3. Select your options

          Qovery propose multiple options that you can select to customize your installation. You can also change some of them later.

        4. Install Qovery

          Click on Create and Deploy to create the cluster and install Qovery on it.

          It will take up to 30 minutes to create the cluster, VPC and install Qovery on it. But you can already configure your first application.

          You should see your new cluster in the list of clusters.

          Show clusters

        - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/aws/index.html b/docs/getting-started/install-qovery/aws/index.html index ab0f848640..af2cd8edf6 100644 --- a/docs/getting-started/install-qovery/aws/index.html +++ b/docs/getting-started/install-qovery/aws/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@
        - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/aws/self-managed-cluster/index.html b/docs/getting-started/install-qovery/aws/self-managed-cluster/index.html index 51ae8bd882..b47a77b9d4 100644 --- a/docs/getting-started/install-qovery/aws/self-managed-cluster/index.html +++ b/docs/getting-started/install-qovery/aws/self-managed-cluster/index.html @@ -24,29 +24,29 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -56,29 +56,29 @@ Read this article to better understand the difference with the Managed Kubernetes by Qovery. In a nutshell, Qovery 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.

        Prerequisites

        • You have a AWS EKS Kubernetes cluster up and running.
        • You have a AWS EKS Kubernetes cluster with at least 4 CPUs and 8GB of RAM.
        • You have kubectl installed and configured to access your AWS EKS Kubernetes cluster.
        • You have helm installed.
        • You have a Qovery account. If you don't have one, please sign up at https://start.qovery.com

        Install Qovery on your AWS EKS cluster

        1. Install Qovery CLI by running the following command:

          To download and install Qovery CLI on any Linux distribution:

          $ curl -s https://get.qovery.com | bash
        2. Authenticate with Qovery by running the following command:

          # Sign up and sign in command
          $ qovery auth

          Your browser window with Qovery sign-up page will open. Follow the instructions to sign up and sign in.

        3. Install Qovery on your AWS EKS cluster:

          qovery cluster install

          Respond to the prompts to install Qovery on your AWS EKS Kubernetes cluster.

        That's it, you can now use Qovery on your AWS EKS cluster.

        Connect to the Qovery console to validate that Qovery is properly installed and start deploying your applications.

        What's Next?

        Now that you have Qovery installed on your Kubernetes cluster, you can check that Qovery is properly installed by following the Validate Installation guide.

        - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/index.html b/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/index.html index e84ed14fae..7676150cfe 100644 --- a/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/index.html +++ b/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

        Managed By Qovery

        Don't be shy, pick the first page you want to read and start your journey with Qovery.

        Quickstart
        Resources
          - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart/index.html b/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart/index.html index 0072bd4689..f4b55c6597 100644 --- a/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart/index.html +++ b/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@
          Resources
            - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/azure/index.html b/docs/getting-started/install-qovery/azure/index.html index 927653c340..d77d03d944 100644 --- a/docs/getting-started/install-qovery/azure/index.html +++ b/docs/getting-started/install-qovery/azure/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@
            - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/azure/self-managed-cluster/index.html b/docs/getting-started/install-qovery/azure/self-managed-cluster/index.html index 6905aaee3d..16af98c904 100644 --- a/docs/getting-started/install-qovery/azure/self-managed-cluster/index.html +++ b/docs/getting-started/install-qovery/azure/self-managed-cluster/index.html @@ -24,29 +24,29 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -56,29 +56,29 @@ Read this article to better understand the difference with the Managed Kubernetes by Qovery. In a nutshell, Qovery 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.

            Prerequisites

            • You have a Azure AKS Kubernetes cluster up and running.
            • You have a Azure AKS Kubernetes cluster with at least 4 CPUs and 8GB of RAM.
            • You have kubectl installed and configured to access your Azure AKS Kubernetes cluster.
            • You have helm installed.
            • You have a Qovery account. If you don't have one, please sign up at https://start.qovery.com

            Install Qovery on your Azure AKS cluster

            1. Install Qovery CLI by running the following command:

              To download and install Qovery CLI on any Linux distribution:

              $ curl -s https://get.qovery.com | bash
            2. Authenticate with Qovery by running the following command:

              # Sign up and sign in command
              $ qovery auth

              Your browser window with Qovery sign-up page will open. Follow the instructions to sign up and sign in.

            3. Install Qovery on your Azure AKS cluster:

              qovery cluster install

              Respond to the prompts to install Qovery on your Azure AKS Kubernetes cluster.

            That's it, you can now use Qovery on your Azure AKS cluster.

            Connect to the Qovery console to validate that Qovery is properly installed and start deploying your applications.

            What's Next?

            Now that you have Qovery installed on your Kubernetes cluster, you can check that Qovery is properly installed by following the Validate Installation guide.

            - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials/index.html b/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials/index.html index 6abb8c92c1..64ad5127c4 100644 --- a/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials/index.html +++ b/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -54,27 +54,27 @@ Follow this documentation to create a new cluster on your organization.

            - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/index.html b/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/index.html index 83a82b0971..b05fda8a12 100644 --- a/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/index.html +++ b/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@
            Resources
              - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/index.html b/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/index.html index d9cfd9fc43..7037fa1b34 100644 --- a/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/index.html +++ b/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

              Quickstart

              Install Qovery on your GCP account in less than 20 minutes. Qovery will create a Kubernetes cluster for you and manage it for you. To install Qovery on an existing Kubernetes cluster, please refer to the dedicated documentation.

              1. Create a Kubernetes cluster

                Now you can create your Kubernetes cluster. Follow this guide to create your Kubernetes cluster.

                Add Cluster

                Note that you can create multiple clusters on the same GCP account with different VPCs. You can also create multiple clusters on different GCP accounts. Qovery will manage them for you.

              2. Attach GCP credentials

                Follow this guide to create your GCP credentials.

                Attach Credentials

                Then attach your credentials to your cluster and click on Create. Then, click on Continue.

              3. Install Qovery

                Click on Create and Deploy to create the cluster and install Qovery on it.

                It will take up to 20 minutes to create the cluster, VPC and install Qovery on it. But you can already configure your first application.

                You should see your new cluster in the list of clusters.

                Show clusters

              - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/gcp/index.html b/docs/getting-started/install-qovery/gcp/index.html index d741124252..70033089d3 100644 --- a/docs/getting-started/install-qovery/gcp/index.html +++ b/docs/getting-started/install-qovery/gcp/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@
              - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/gcp/self-managed-cluster/index.html b/docs/getting-started/install-qovery/gcp/self-managed-cluster/index.html index 45b5bce29e..8af48b2a3c 100644 --- a/docs/getting-started/install-qovery/gcp/self-managed-cluster/index.html +++ b/docs/getting-started/install-qovery/gcp/self-managed-cluster/index.html @@ -24,29 +24,29 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -56,29 +56,29 @@ Read this article to better understand the difference with the Managed Kubernetes by Qovery. In a nutshell, Qovery 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.

              Prerequisites

              • You have a GCP GKE Kubernetes cluster up and running.
              • You have a GCP GKE Kubernetes cluster with at least 4 CPUs and 8GB of RAM.
              • You have kubectl installed and configured to access your GCP GKE Kubernetes cluster.
              • You have helm installed.
              • You have a Qovery account. If you don't have one, please sign up at https://start.qovery.com

              Install Qovery on your GCP GKE cluster

              1. Install Qovery CLI by running the following command:

                To download and install Qovery CLI on any Linux distribution:

                $ curl -s https://get.qovery.com | bash
              2. Authenticate with Qovery by running the following command:

                # Sign up and sign in command
                $ qovery auth

                Your browser window with Qovery sign-up page will open. Follow the instructions to sign up and sign in.

              3. Install Qovery on your GCP GKE cluster:

                qovery cluster install

                Respond to the prompts to install Qovery on your GCP GKE Kubernetes cluster.

              That's it, you can now use Qovery on your GCP GKE cluster.

              Connect to the Qovery console to validate that Qovery is properly installed and start deploying your applications.

              What's Next?

              Now that you have Qovery installed on your Kubernetes cluster, you can check that Qovery is properly installed by following the Validate Installation guide.

              - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/index.html b/docs/getting-started/install-qovery/index.html index 081bc7c4a0..230e6088b7 100644 --- a/docs/getting-started/install-qovery/index.html +++ b/docs/getting-started/install-qovery/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -54,27 +54,27 @@ Choose Cluster 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 Self-Managed otherwise.

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

              Feature/AspectCluster Managed by Qovery (recommended)Self-Managed Cluster (advanced)
              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
              Managed Services

              Here is the list of managed services provided by Qovery with the Kubernetes Managed by Qovery approach:

              • 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

              A more detailed comparison is available on our blog

              - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/kubernetes/byok-config/index.html b/docs/getting-started/install-qovery/kubernetes/byok-config/index.html index 6d7a1b1cf5..79a32fe68b 100644 --- a/docs/getting-started/install-qovery/kubernetes/byok-config/index.html +++ b/docs/getting-started/install-qovery/kubernetes/byok-config/index.html @@ -24,29 +24,29 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -56,29 +56,29 @@ 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 Qovery 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

              RequiredNo (but strongly recommended)
              If deployedRetrieve and store application's log history
              If missingYou'll have live logs, but you will miss log history for debugging purpose

              Qovery uses Loki to store your logs in a S3 compatible bucket and Promtail to collect your logs.

              Loki

              Here is a configuration in Memory (no persistence) for 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

              A configuration example compatible with all providers:

              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

              RequiredNo (but strongly recommended)
              If deployedCert-manager helps you to get TLS certificates through Let's Encrypt
              If missingWithout it, you will not be able to automatically get TLS certificates

              Qovery uses Cert Manager to automatically get TLS certificates for your applications.

              Cert Manager

              Here is the minimal setup for all cloud providers:

              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

              RequiredNo (but if you're using Qovery DNS Provider)
              If deployedRequired to get Let's Encrypt TLS if Qovery DNS Provider is used
              If missingWithout it, you will not be able to automatically get TLS certificates with Qovery DNS Provider

              A configuration example compatible with all providers:

              qovery-cert-manager-webhook:
              fullnameOverride: qovery-cert-manager-webhook
              certManager:
              # set the same namespace than cert-manager
              namespace: qovery
              serviceAccountName: cert-manager
              secret:
              apiUrl: *qoveryDnsUrl
              apiKey: *jwtToken

              Cert Manager Configs

              RequiredNo
              If deployedThis is an helper to deploy cert-manager config. But you can manually set it
              If missingInstalling Cert-manager is not enough, you have to configure it to get TLS working

              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

              RequiredNo (but strongly recommended)
              If deployedMandatory if you want to retrive pod metrics for the Qovery agent and if you want to be able to use the horizontal pod scaling
              If missingNo HPA and no application metrics in the QOveyr console
              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
              - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/kubernetes/faq/index.html b/docs/getting-started/install-qovery/kubernetes/faq/index.html index 2f7713a67e..3a741a68c7 100644 --- a/docs/getting-started/install-qovery/kubernetes/faq/index.html +++ b/docs/getting-started/install-qovery/kubernetes/faq/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

              FAQ

              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 moment, you can't. But please contact us to discuss it. We will be happy to help you.

              - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/kubernetes/index.html b/docs/getting-started/install-qovery/kubernetes/index.html index 773bfccdea..3c4ba506f2 100644 --- a/docs/getting-started/install-qovery/kubernetes/index.html +++ b/docs/getting-started/install-qovery/kubernetes/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@
              Resources
                - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/kubernetes/quickstart/index.html b/docs/getting-started/install-qovery/kubernetes/quickstart/index.html index d722cc886b..0e9656c4ab 100644 --- a/docs/getting-started/install-qovery/kubernetes/quickstart/index.html +++ b/docs/getting-started/install-qovery/kubernetes/quickstart/index.html @@ -24,29 +24,29 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -56,29 +56,29 @@ Read this article to better understand the difference with the Managed Kubernetes by Qovery. In a nutshell, Qovery 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.

                Prerequisites

                • You have a Kubernetes Kubernetes cluster up and running.
                • You have a Kubernetes Kubernetes cluster with at least 4 CPUs and 8GB of RAM.
                • You have kubectl installed and configured to access your Kubernetes Kubernetes cluster.
                • You have helm installed.
                • You have a Qovery account. If you don't have one, please sign up at https://start.qovery.com

                Install Qovery on your Kubernetes cluster

                1. Install Qovery CLI by running the following command:

                  To download and install Qovery CLI on any Linux distribution:

                  $ curl -s https://get.qovery.com | bash
                2. Authenticate with Qovery by running the following command:

                  # Sign up and sign in command
                  $ qovery auth

                  Your browser window with Qovery sign-up page will open. Follow the instructions to sign up and sign in.

                3. Install Qovery on your Kubernetes cluster:

                  qovery cluster install

                  Respond to the prompts to install Qovery on your Kubernetes Kubernetes cluster.

                That's it, you can now use Qovery on your Kubernetes cluster.

                Connect to the Qovery console to validate that Qovery is properly installed and start deploying your applications.

                What's Next?

                Now that you have Qovery installed on your Kubernetes cluster, you can check that Qovery is properly installed by following the Validate Installation guide.

                - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/kubernetes/validate-installation/index.html b/docs/getting-started/install-qovery/kubernetes/validate-installation/index.html index a04cda74d1..c0f93ba2c4 100644 --- a/docs/getting-started/install-qovery/kubernetes/validate-installation/index.html +++ b/docs/getting-started/install-qovery/kubernetes/validate-installation/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -55,27 +55,27 @@ 2) retrieve the running status of the application from the element next to the Live logs tab

                Test container

                Step 2: verify application public exposure and TLS

                1. Expose container publicly

                  Open the settings of the container created in the step 1. Open the section Port

                  Add one port with:

                  • Application port: 9898
                  • Protocol: HTTP
                  • Publicly exposed: true

                  Add the port and then click on Re-deploy now banner.

                2. Follow the deployment

                  The application will start the deployment and you can follow it opening the Log button or by pressing on the Deployment status

                  Test container

                  After a few seconds, the deployment should end and the message Deployment of Container succeeded should be displayed in the deployment logs.

                3. Check the accessibility

                  Click on the "Link" button and select one of the URLs of the list.

                  Application Link

                  You should be able to access the podinfo homepage with a valid certificate.

                Step 3: verify storage availability

                1. Create a database

                  Go back to the environment page and create a new service of type Database.

                  Fill the fields this way:

                  • Name: test-db
                  • Database Mode: Container
                  • Database type: Mysql
                  • version: select one from the list
                  • accessibility: private

                  Click on Continue until the installation recap is displayed. Now click on Create and deploy.

                2. Follow the deployment

                  The databse will start the deployment and you can follow it opening the Log button or by pressing on the Deployment status

                  After a few seconds, the deployment should end and the message Deployment of Database succeeded should be displayed in the deployment logs.

                  You should now see at least one pod running on your cluster with the specified container and you should be able to access your database from within you cluster (you can retrieve the connection string via the button Connection URI available in the database overview targetCPUUtilizationPercentage)

                - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/local/index.html b/docs/getting-started/install-qovery/local/index.html index 66a560fe3c..59d8c136a5 100644 --- a/docs/getting-started/install-qovery/local/index.html +++ b/docs/getting-started/install-qovery/local/index.html @@ -24,29 +24,29 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -57,29 +57,29 @@
                Go to https://console.qovery.com to create your first environment on this cluster 'hello-local-cluster'
                """"""""""""""""""""""""""""""""""""""""""""
              • Access the Qovery dashboard by visiting console.qovery.com.

              • Well done, you have successfully installed Qovery on your local machine. You can now start deploying your applications and experience the Qovery experience.

                Cleanup your local environment

                To clean up your local environment, run the following command:

                qovery demo destroy

                That's it! You have successfully removed the Qovery demo cluster from your local machine.

                - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/create-credentials/index.html b/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/create-credentials/index.html index ddcae72cad..132707d9a0 100644 --- a/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/create-credentials/index.html +++ b/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/create-credentials/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                Create Credentials

                Generate your Scaleway credentials

                1. Connect to your Scaleway console

                2. Go to IAM

                3. Go to Applications

                4. Create a new application for your project

                5. Generate your new API key from your application view

                  Set up the the preferred `Project` for `Object Storage` with your Scaleway Project
                6. Save the generated access key id and secret access key.

                7. Go to Policies

                8. Create a new policy with Principal linked to the application you just created.

                9. Set the scope of the policy to your project

                10. Select the following rules for your policy

                  • Containers permissions
                  • Network Service permissions
                  • Compute permissions
                  • Storage permissions
                  • VPC permissions
                11. Create your policy

                12. Get your organization id in your organization settings

                13. Get your project id on your project dashboard

                Well done!! You now have your Scaleway access key id, secret access key, organization_id and project id; It is time to connect Qovery to your Scaleway account.

                - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/faq/index.html b/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/faq/index.html index 74b19bb186..bc44a35190 100644 --- a/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/faq/index.html +++ b/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/faq/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -54,27 +54,27 @@ To make it works, Qovery rely on Kubernetes for stateless apps (containers), and Scaleway for stateful apps (databases, storage...).

                Read more on how Qovery works behind the scene.

                Kubernetes

                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.

                Managed services

                Scaleway 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 Scaleway account.
                • Your configuration is encrypted on your Scaleway 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 Scaleway

                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/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/index.html b/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/index.html index 63fd9e1e42..d033160e00 100644 --- a/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/index.html +++ b/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@
                Resources
                  - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/index.html b/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/index.html index cd9eb973a7..1de0151315 100644 --- a/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/index.html +++ b/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                  Quickstart

                  Install Qovery on your Scaleway account in less than 20 minutes. Qovery will create a Kubernetes cluster for you and manage it for you. To install Qovery on an existing Kubernetes cluster, please refer to the dedicated documentation.

                  1. Create a Kubernetes cluster

                    Now you can create your Kubernetes cluster. Follow this guide to create your Kubernetes cluster.

                    Add Cluster

                    Note that you can create multiple clusters on the same Scaleway account with different VPCs. You can also create multiple clusters on different Scaleway accounts. Qovery will manage them for you.

                  2. Attach Scaleway credentials

                    Follow this guide to create your Scaleway credentials.

                    Create Credentials

                    Then attach your credentials to your cluster and click on Create. Then, click on Continue.

                  3. Install Qovery

                    Click on Create and Deploy to create the cluster and install Qovery on it.

                    It will take up to 20 minutes to create the cluster, VPC and install Qovery on it. But you can already configure your first application.

                    You should see your new cluster in the list of clusters.

                    Show clusters

                  - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/scaleway/index.html b/docs/getting-started/install-qovery/scaleway/index.html index f8b930d480..373b82e434 100644 --- a/docs/getting-started/install-qovery/scaleway/index.html +++ b/docs/getting-started/install-qovery/scaleway/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@
                  - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/install-qovery/scaleway/self-managed-cluster/index.html b/docs/getting-started/install-qovery/scaleway/self-managed-cluster/index.html index 023a1f5769..46334f789a 100644 --- a/docs/getting-started/install-qovery/scaleway/self-managed-cluster/index.html +++ b/docs/getting-started/install-qovery/scaleway/self-managed-cluster/index.html @@ -24,29 +24,29 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -56,29 +56,29 @@ Read this article to better understand the difference with the Managed Kubernetes by Qovery. In a nutshell, Qovery 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.

                  Prerequisites

                  • You have a Scaleway Kapsule Kubernetes cluster up and running.
                  • You have a Scaleway Kapsule Kubernetes cluster with at least 4 CPUs and 8GB of RAM.
                  • You have kubectl installed and configured to access your Scaleway Kapsule Kubernetes cluster.
                  • You have helm installed.
                  • You have a Qovery account. If you don't have one, please sign up at https://start.qovery.com

                  Install Qovery on your Scaleway Kapsule cluster

                  1. Install Qovery CLI by running the following command:

                    To download and install Qovery CLI on any Linux distribution:

                    $ curl -s https://get.qovery.com | bash
                  2. Authenticate with Qovery by running the following command:

                    # Sign up and sign in command
                    $ qovery auth

                    Your browser window with Qovery sign-up page will open. Follow the instructions to sign up and sign in.

                  3. Install Qovery on your Scaleway Kapsule cluster:

                    qovery cluster install

                    Respond to the prompts to install Qovery on your Scaleway Kapsule Kubernetes cluster.

                  That's it, you can now use Qovery on your Scaleway Kapsule cluster.

                  Connect to the Qovery console to validate that Qovery is properly installed and start deploying your applications.

                  What's Next?

                  Now that you have Qovery installed on your Kubernetes cluster, you can check that Qovery is properly installed by following the Validate Installation guide.

                  - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/getting-started/what-is-qovery/index.html b/docs/getting-started/what-is-qovery/index.html index b39345af2c..5823f72926 100644 --- a/docs/getting-started/what-is-qovery/index.html +++ b/docs/getting-started/what-is-qovery/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                  What is Qovery?

                  Qovery is a DevOps Automation Platform that eliminates your DevOps hiring needs. Provision and maintain a secure and compliant infrastructure in hours - not months!

                  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 DevOps Automation 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 a50e3a0fff..f66e0acf9f 100644 --- a/docs/getting-started/whats-next/index.html +++ b/docs/getting-started/whats-next/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -54,27 +54,27 @@ subsections:

                  Using Qovery
                  Resources
                    - + - + - + - + - + - + - + - + - + - + diff --git a/docs/index.html b/docs/index.html index 5168d17cf5..f2b9dcfbf4 100644 --- a/docs/index.html +++ b/docs/index.html @@ -20,13 +20,13 @@ - + - + - + - + @@ -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 5d6069fd90..91f5346776 100644 --- a/docs/security-and-compliance/backup-and-restore/index.html +++ b/docs/security-and-compliance/backup-and-restore/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                    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 2b05391ca0..6f27bf34da 100644 --- a/docs/security-and-compliance/encryption/index.html +++ b/docs/security-and-compliance/encryption/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                    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 1a9ab09260..fe208ac682 100644 --- a/docs/security-and-compliance/gdpr/index.html +++ b/docs/security-and-compliance/gdpr/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                    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 cbeef7f463..00b2050ba2 100644 --- a/docs/security-and-compliance/index.html +++ b/docs/security-and-compliance/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@
                    Resources
                      - + - + - + - + - + - + - + - + - + - + diff --git a/docs/security-and-compliance/soc2/index.html b/docs/security-and-compliance/soc2/index.html index 9aec215db1..457cc38ab4 100644 --- a/docs/security-and-compliance/soc2/index.html +++ b/docs/security-and-compliance/soc2/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -54,27 +54,27 @@ 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 b321c6a565..a6ee4d4ed3 100644 --- a/docs/useful-resources/faq/index.html +++ b/docs/useful-resources/faq/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -55,27 +55,27 @@ 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, you can connect directly to your application with a shell by clicking on the Qovery cloud shell button (1):

                      Qovery Cloud Shell

                      Then you just have to select the pod (2) and the container (3).

                      You can also 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.

                      How can I contact you?

                      Feel free to join our forum or contact us by email at hello (at) qovery.com or via the Intercom chat.

                      - + - + - + - + - + - + - + - + - + - + diff --git a/docs/useful-resources/help-and-support/index.html b/docs/useful-resources/help-and-support/index.html index bb70909ae1..c14b0bb6e7 100644 --- a/docs/useful-resources/help-and-support/index.html +++ b/docs/useful-resources/help-and-support/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                      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 11da5db368..c18c3ba4d8 100644 --- a/docs/using-qovery/audit-logs/index.html +++ b/docs/using-qovery/audit-logs/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                      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 27f9f5ac5a..b58c88808d 100644 --- a/docs/using-qovery/configuration/advanced-settings/index.html +++ b/docs/using-qovery/configuration/advanced-settings/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                      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.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

                      Affinity

                      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

                      Lifecycle Hooks

                      deployment.lifecycle.post_start_exec_command

                      TypeDescriptionDefault Value
                      stringAllows you to run a command after the application is started. The command should be a shell command or script.``

                      deployment.lifecycle.pre_stop_exec_command

                      TypeDescriptionDefault Value
                      stringAllows you to run a command before the application is stopped. The command should be a shell command or script. Qovery requires the sh shell by default and sets a sleep of 15 seconds to let Nginx update its config. Avoiding error codes returned during a rolling update.["/bin/sh", "-c", "sleep 15"]

                      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.add_headers

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

                      network.ingress.proxy_set_headers

                      TypeDescriptionDefault Value
                      stringAllows you to specify additional headers to the incoming requests. The header values are 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

                      hpa.memory.average_utilization_percent

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

                      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

                      Resources

                      resources.override.limit.cpu_in_milli

                      TypeDescriptionUse CaseDefault Value
                      integerDefine the CPU overcommit (pod cpu limit) of the service.A service require more CPU at startup than during the running phase. You can reduce the configured CPU for the service and just increase the resources.override.limit.cpu_in_milli to reduce the resources used by the service at runtimenull (i.e. request = limit)

                      This settings can be changed only if the advanced settings allow_service_cpu_overcommit is set to true.

                      resources.override.limit.ram_in_mib

                      TypeDescriptionUse CaseDefault Value
                      integerDefine the memory overcommit (pod memory limit) of the service.A service require more memory at startup than during the running phase. You can reduce the configured memory for the service and just increase the resources.override.limit.ram_in_mib to reduce the resources used by the service at runtimenull (i.e. request = limit)

                      This settings can be changed only if the advanced settings allow_service_ram_overcommit is set to true.

                      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``

                      security.automount_service_account_token

                      TypeDescriptionDefault Value
                      booleanAutomount Kubernetes service account token to have access to Kubernetes API from podsfalse
                      - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/application-health-checks/index.html b/docs/using-qovery/configuration/application-health-checks/index.html index 96196ea681..89801050d5 100644 --- a/docs/using-qovery/configuration/application-health-checks/index.html +++ b/docs/using-qovery/configuration/application-health-checks/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -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 8fd0b32dd9..1f8ee8f148 100644 --- a/docs/using-qovery/configuration/application/index.html +++ b/docs/using-qovery/configuration/application/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -60,27 +60,27 @@ 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 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.

                      Advanced Settings

                      You can further customize the service behaviour via the service advanced settings. Check this documentation to know more.

                      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/index.html b/docs/using-qovery/configuration/cloud-service-provider/index.html index 7e1866cdf5..d4ea882d97 100644 --- a/docs/using-qovery/configuration/cloud-service-provider/index.html +++ b/docs/using-qovery/configuration/cloud-service-provider/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                      Cloud Service Provider

                      FAQ

                      I don't find my Cloud provider, what should I do?

                      Your Cloud provider is probably going to be supported in the near future. Contact us to see how we can help you.

                      - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/cluster-advanced-settings/index.html b/docs/using-qovery/configuration/cluster-advanced-settings/index.html index d2118ab95e..361b0bf629 100644 --- a/docs/using-qovery/configuration/cluster-advanced-settings/index.html +++ b/docs/using-qovery/configuration/cluster-advanced-settings/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                      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)

                      gcp.vpc.enable_flow_logs

                      TypeDescriptionDefault Value
                      booleanEnable VPC flow logs on the cluster VPC (on each VPC subnetworks). See GCP VPC logs flow documentation.false

                      gcp.vpc.flow_logs_sampling

                      TypeDescriptionDefault Value
                      floatSet VPC logs flow sampling percentage. Value should be within [0.0 (no sampling), 1.0 (all logs)] range.0.0

                      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

                      nginx.controller.enable_client_ip

                      TypeDescriptionDefault Value
                      boolEnables ngx_http_realip_module module.false

                      nginx.controller.log_format_upstream

                      TypeDescriptionDefault Value
                      stringAllows to customize nginx log-format.null

                      nginx.controller.log_format_escaping

                      TypeDescriptionDefault Value
                      stringAllows to customize nginx log-format-escaping setting, possible values are: Default, JSON, None.Default

                      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"]

                      Service

                      allow_service_cpu_overcommit

                      TypeDescriptionDefault Value
                      booleanAuthorize CPU overcommit (limit > request) for the services deployed within this clusterfalse

                      Once enabled, you can update the advanced setting resources.override.limit.cpu_in_mib of your service.

                      allow_service_ram_overcommit

                      TypeDescriptionDefault Value
                      booleanAuthorize memory overcommit (limit > request) for the services deployed within this clusterfalse

                      Once enabled, you can update the advanced setting resources.override.limit.ram_in_mib of your service.

                      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 cluster. Its value can be changed after the cluster installation via a re-deploy without any downtime.Admins

                      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

                      aws.eks.encrypt_secrets_kms_key_arn

                      TypeDescriptionDefault Value
                      stringAllows you to activate KMS encryption of your Kubernetes secrets. Specify the key ARN of your AWS KMS key.

                      storageclass.fast_ssd

                      TypeDescriptionDefault Value
                      stringSpecify the kubernetes storageClass to be used for the storage attached to your container databases and applicationsdifferent by cloud provider
                      - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/clusters/index.html b/docs/using-qovery/configuration/clusters/index.html index b6240feac1..7b081ad005 100644 --- a/docs/using-qovery/configuration/clusters/index.html +++ b/docs/using-qovery/configuration/clusters/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -60,27 +60,27 @@ This 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.

                      This operation will delete:

                      • 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.
                      • Qovery organization: the configuration of this cluster and any linked environment.

                      2) Delete Cluster on cloud provider and Qovery configuration

                      This option shall be chosen when the cluster delete operation with the Default option fails since you have manually modified/deleted the RDS instances created by Qovery on your cloud provider account.

                      This operation will delete:

                      • 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.
                      • Qovery organization: the configuration of this cluster and any linked environment.

                      3) Delete Qovery config only

                      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.

                      This operation will delete:

                      • 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.
                      • Qovery organization: the configuration of this cluster and any linked environment.

                      Once confirmed, the cluster status turns to Deleting... (red status) and once the deletion is complete, the cluster is removed from your organization settings.

                      Audit logs

                      To get the cluster filtered audit logs, open the ... section and press See audit logs.

                      You will be redirected to the audit logs section. A filter on the dedicated cluster will be applied. You only see the audit logs regarding cluster operations.

                      Get your cluster id

                      To get your Qovery cluster id, open the ... section and press Copy identifier.

                      The cluster id in Qovery will be in your clipboard.

                      Get your cluster kubeconfig file

                      If you need to get your kubeconfig file, open the ... section and press Get Kubeconfig.

                      Then the kubeconfig yaml file will be automatically downloaded.

                      Logs

                      Qovery allows you to access the logs of your cluster in order to follow its installation or investigate any issue happening on it.

                      To access the logs you need to open the cluster, click the log button

                      Cluster Logs

                      A new window is opened, displaying the logs of the cluster.

                      Cluster Logs

                      The tab system on the right allows you to access the cluster information and, if an error occurs, the detail of the error.

                      Cluster Logs

                      Generating an SSH Key for Your Cluster

                      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:

                      1. On your computer, open a terminal.

                      2. Run ssh-keygen -t, followed by the key type and an optional comment.

                        For example, you can enter ssh-keygen -t rsa -b 2048 -C "<comment>".

                      3. Press Enter.

                        You should get an output similar to:

                        {
                        Generating public/private ed25519 key pair.
                        Enter file in which to save the key (/home/user/.ssh/id_ed25519):
                        }
                      4. Accept the suggested filename and directory, unless you want to save your SSH key in a specific directory where you store other keys.

                      5. Enter a passphrase:

                        {
                        Enter passphrase (empty for no passphrase):
                        Enter same passphrase again:
                        }

                        A confirmation is displayed, including information about where your files are stored.

                      6. Access the public key and copy its value
                        {
                        cat /home/user/.ssh/id_ed25519.pub | pbcopy
                        }

                        Note: Replace the .pub key path with the one where is located the key you have previously generated

                      You can add the generated public SSH key at cluster creation (see Creating a Cluster), or later from your cluster settings.

                      To do so:

                      Use custom domain and wildcard TLS for the whole cluster (beta)

                      By default, Qovery provides a domain (ex 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.

                      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 Let's Encrypt quotas.

                      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.

                      At the moment, Qovery only supports wildcard TLS certificates with 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.

                      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 My Profile. In the API Tokens section, click on Create Token. In the Create Custom Token section, select the following permissions:

                      • API token a descriptive name: Qovery domain your domain name
                      • Permissions:
                        • Zone - DNS - Edit
                        • Zone - Zone - Read
                      • Zone Resources:
                        • Include - Specific zone - your domain name

                      To finish, click on Continue to Summary and Create Token. Save the token somewhere safe, you will need it later.

                      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.

                      Cleaning up a Cluster from your AWS Account

                      To clean up a Qovery cluster from your cloud provider account, go to AWS Console>Services>Management & Governance>Resource Groups & Tag Editor> Create Resource Group:

                      AWS Console Cluster Cleanup

                      StepDescription
                      1In the Group type area, select Tag based.
                      2In the Tags field of the Grouping criteria area, enter ClusterId.
                      3Click Add.
                      4Click Preview Resources.
                      All your Qovery clusters are now displayed in the Group resources table, and you can delete them by hand.
                      - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/cronjob/index.html b/docs/using-qovery/configuration/cronjob/index.html index aa9b7aaf14..6070db3e8d 100644 --- a/docs/using-qovery/configuration/cronjob/index.html +++ b/docs/using-qovery/configuration/cronjob/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -57,27 +57,27 @@ 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.

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

                      Auto Deploy

                      See the Deploying with auto-deploy feature section.

                      Extra labels/annotations

                      Add your extra annotation/label groups. See the Add annotation/label group section for more information.

                      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.
                      • Timezone: select a valid timezone identifier. After being deployed, the job will be executed following the defined timezone. Etc/UTC is the default value.
                      • Image Entrypoint: the entrypoint to be used to launch your job (not mandatory)
                      • CMD Arguments: the arguments to be passed to launch your application (not mandatory) separated with a space. Example: rails -h 0.0.0.0 -p 8080 string "complex arg".
                      • 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

                      Deployment Restrictions

                      This section allows to specify which changes on your repository should trigger an auto-deploy (if enabled). To know more about how to configure your Deployment Restrictions, have a look at the deployment restrictions section.

                      Advanced Settings

                      You can further customize the service behaviour via the service advanced settings. Check this documentation to know more.

                      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 eca5db4221..3153246067 100644 --- a/docs/using-qovery/configuration/database/index.html +++ b/docs/using-qovery/configuration/database/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -56,27 +56,27 @@ It is up to the user or Cloud provider Administrator to delete it manually.

                      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 94186966fb..dfda094ef4 100644 --- a/docs/using-qovery/configuration/database/mongodb/index.html +++ b/docs/using-qovery/configuration/database/mongodb/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                      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 f5d400efbd..3ab5a8d97f 100644 --- a/docs/using-qovery/configuration/database/mysql/index.html +++ b/docs/using-qovery/configuration/database/mysql/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                      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 01728c45ac..de70a07ae5 100644 --- a/docs/using-qovery/configuration/database/postgresql/index.html +++ b/docs/using-qovery/configuration/database/postgresql/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                      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 d6972af126..3918cada8d 100644 --- a/docs/using-qovery/configuration/database/redis/index.html +++ b/docs/using-qovery/configuration/database/redis/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                      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 482e780efd..d9e2959e0e 100644 --- a/docs/using-qovery/configuration/deployment-rule/index.html +++ b/docs/using-qovery/configuration/deployment-rule/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -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 ade8397a95..cd7c70ae51 100644 --- a/docs/using-qovery/configuration/environment-variable/index.html +++ b/docs/using-qovery/configuration/environment-variable/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -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 5725fde3ef..279011bdd9 100644 --- a/docs/using-qovery/configuration/environment/index.html +++ b/docs/using-qovery/configuration/environment/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -55,27 +55,27 @@ 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 index 308de1bd44..eeafe98a93 100644 --- a/docs/using-qovery/configuration/helm/index.html +++ b/docs/using-qovery/configuration/helm/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -59,27 +59,27 @@ 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.

                      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.

                      Advanced Settings

                      You can further customize the service behaviour via the service advanced settings. Check this documentation to know more.

                      Delete a Helm

                      1. Choose your helm

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

                      - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/index.html b/docs/using-qovery/configuration/index.html index 9acc6a3f47..932d4f4554 100644 --- a/docs/using-qovery/configuration/index.html +++ b/docs/using-qovery/configuration/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@
                      - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/lifecycle-job/index.html b/docs/using-qovery/configuration/lifecycle-job/index.html index 7ad94e461a..b3bfe1e277 100644 --- a/docs/using-qovery/configuration/lifecycle-job/index.html +++ b/docs/using-qovery/configuration/lifecycle-job/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -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.

                      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. Select the environment event you want to force.

                      4. 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

                      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)

                      Auto Deploy

                      See the Deploying with auto-deploy feature section.

                      Extra labels/annotations (optional)

                      Add your extra annotation/label groups. See the Add annotation/label group section for more information.

                      Dockerfile

                      If your job is built via the Qovery CI (Source="Git Repository"), this section allows you to define the Dockerfile location.

                      Two options are available, depending on where you want to store the Dockerfile:

                      Git repository

                      Specify the location of your Dockerfile in Dockefile path field.

                      RAW Dockerfile

                      Qovery can store and inject for you the Dockerfile instead of storing it into your repository.

                      If you don't have one, you can use the docker init command to generate one for your application (check the documentation here).

                      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 application (not mandatory) separated with a space. Example: rails -h 0.0.0.0 -p 8080 string "complex arg".
                      • 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.

                      Deployment Restrictions

                      This section allows to specify which changes on your repository should trigger an auto-deploy (if enabled). To know more about how to configure your Deployment Restrictions, have a look at the deployment restrictions section.

                      Advanced Settings

                      You can further customize the service behaviour via the service advanced settings. Check this documentation to know more.

                      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/object-storage/index.html b/docs/using-qovery/configuration/object-storage/index.html index a23d537d51..f53c286530 100644 --- a/docs/using-qovery/configuration/object-storage/index.html +++ b/docs/using-qovery/configuration/object-storage/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -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 1eab93deaf..f5eb9aa497 100644 --- a/docs/using-qovery/configuration/organization/api-token/index.html +++ b/docs/using-qovery/configuration/organization/api-token/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                      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 e88a5f6518..95f824fbd7 100644 --- a/docs/using-qovery/configuration/organization/container-registry/index.html +++ b/docs/using-qovery/configuration/organization/container-registry/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -54,27 +54,27 @@ 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 ec23fd273e..2f9158c8a6 100644 --- a/docs/using-qovery/configuration/organization/git-repository-access/index.html +++ b/docs/using-qovery/configuration/organization/git-repository-access/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -58,27 +58,27 @@ Please note that the repositories must belong to the same Github organization, we do not support yet a multi-github organization setup

                      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 index a354a1fd9f..32c89e5cfc 100644 --- a/docs/using-qovery/configuration/organization/helm-repository/index.html +++ b/docs/using-qovery/configuration/organization/helm-repository/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -54,27 +54,27 @@ You can delete an existing helm repository by clicking on the "Trash" button next to it

                      Helm

                      - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/organization/index.html b/docs/using-qovery/configuration/organization/index.html index 65ea2ad113..422bf5354b 100644 --- a/docs/using-qovery/configuration/organization/index.html +++ b/docs/using-qovery/configuration/organization/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -55,27 +55,27 @@ 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
                      Labels annotations
                      Members rbac
                      - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/organization/labels-annotations/index.html b/docs/using-qovery/configuration/organization/labels-annotations/index.html index fe583d7dfb..c36a908341 100644 --- a/docs/using-qovery/configuration/organization/labels-annotations/index.html +++ b/docs/using-qovery/configuration/organization/labels-annotations/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -59,27 +59,27 @@ If this annotation group was already used in your services. You will have to redeploy them for removing the annotations linked to your services.

                      - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/organization/members-rbac/index.html b/docs/using-qovery/configuration/organization/members-rbac/index.html index d1410d8ba6..2319dc9093 100644 --- a/docs/using-qovery/configuration/organization/members-rbac/index.html +++ b/docs/using-qovery/configuration/organization/members-rbac/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -56,27 +56,27 @@ 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 823db1a0bd..11b21678f6 100644 --- a/docs/using-qovery/configuration/project/index.html +++ b/docs/using-qovery/configuration/project/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                      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 4f544619f4..5da1b9d984 100644 --- a/docs/using-qovery/configuration/provider/index.html +++ b/docs/using-qovery/configuration/provider/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                      Provider

                      Resources
                        - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/configuration/service-health-checks/index.html b/docs/using-qovery/configuration/service-health-checks/index.html index fb57df52b9..d6090cc32a 100644 --- a/docs/using-qovery/configuration/service-health-checks/index.html +++ b/docs/using-qovery/configuration/service-health-checks/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -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/user-account/index.html b/docs/using-qovery/configuration/user-account/index.html index 3bdf13bbeb..40a5ccfcff 100644 --- a/docs/using-qovery/configuration/user-account/index.html +++ b/docs/using-qovery/configuration/user-account/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -55,27 +55,27 @@ 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
                        • Timezone: used in the Qovery console for the dates display. To change it, modify the timezone used in your browser settings.
                        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 a08c57f0f6..31a45cffd4 100644 --- a/docs/using-qovery/deployment/deploying-with-auto-deploy/index.html +++ b/docs/using-qovery/deployment/deploying-with-auto-deploy/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -55,27 +55,27 @@ -- use a auto-deploy containers endpoint that will trigger the deployment of any service using the same image within the organization and having the auto-deploy feature activated - + - + - + - + - + - + - + - + - + - + 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 fd5694f7f2..b331e311de 100644 --- a/docs/using-qovery/deployment/deploying-with-ci-cd/index.html +++ b/docs/using-qovery/deployment/deploying-with-ci-cd/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                          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 e0b8b68ab6..d6e81c10df 100644 --- a/docs/using-qovery/deployment/deployment-actions/index.html +++ b/docs/using-qovery/deployment/deployment-actions/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -59,27 +59,27 @@ 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 and stop the execution of the deployment pipeline. This action is available only if the current deployment status is Queued or Building or Deploying.

                            If a deployment of a service A is already ongoing, the cancel operation will stop the deployment execution and rollback the service A to the previous version. Any service already deployed during the pipeline execution will not rollback to the previous version.

                            For Lifecycle Jobs, the cancel operation is not taken into account unless it is forced via the checkbox available in the "Deployment cancel" modal.

                            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 bae709b871..127620a9fa 100644 --- a/docs/using-qovery/deployment/deployment-history/index.html +++ b/docs/using-qovery/deployment/deployment-history/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                            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 c6defa9965..134b8477b0 100644 --- a/docs/using-qovery/deployment/deployment-pipeline/index.html +++ b/docs/using-qovery/deployment/deployment-pipeline/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -54,27 +54,27 @@ 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 78959dd042..29267857a4 100644 --- a/docs/using-qovery/deployment/deployment-strategies/index.html +++ b/docs/using-qovery/deployment/deployment-strategies/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                              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 5cea171067..b0f3106572 100644 --- a/docs/using-qovery/deployment/image-mirroring/index.html +++ b/docs/using-qovery/deployment/image-mirroring/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                Image Mirroring

                                When Qovery is running on your infrastructure, it requires an image registry to store the images built via the Qovery CI and to mirror the images deployed from a 3rd party container registry.

                                This mirroring registry is available and configurable within the Qovery interface

                                Mirroring Repository

                                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

                                In order to speed up the image build, we are using remote caches (available in AWS, GCP and Scaleway). It will avoid building the image from scratch, only the layers that changed will be built.

                                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.

                                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.

                                Disabling the mirroring

                                If you want to reduce the deployment time by avoiding the mirroring operation, you can push your built images directly into the Mirroring registry.

                                Push the images in a image registry repository having the same name of the image you want to deploy.

                                Example on AWS

                                Let's say you have a container image called nginx that you build on your CI and the container registry associated with your cluster is https://32432542.dkr.ecr.eu-west-3.amazonaws.com.

                                You can push this image on the mirroring registry within the repository nginx, avoiding the mirroring operation: https://32432542.dkr.ecr.eu-west-3.amazonaws.com/nginx

                                - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/deployment/index.html b/docs/using-qovery/deployment/index.html index 6602382ee8..0301108b9c 100644 --- a/docs/using-qovery/deployment/index.html +++ b/docs/using-qovery/deployment/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -56,27 +56,27 @@ 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.
                              • 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.
                              • The Qovery engine pulls the code from your repository.
                              • 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).
                              • The Qovery engine creates the load balancers and configure the network.
                              • The Qovery engine creates a namespace within the Kubernetes cluster and deploys the application.
                              • 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 962fb1c709..90112cebe3 100644 --- a/docs/using-qovery/deployment/logs/index.html +++ b/docs/using-qovery/deployment/logs/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                  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

                                  If you have several pods within your application, you have the possiblity to filter the logs by pod.

                                  Log content

                                  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 849372d8f8..54809fb95b 100644 --- a/docs/using-qovery/deployment/running-and-deployment-statuses/index.html +++ b/docs/using-qovery/deployment/running-and-deployment-statuses/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -54,27 +54,27 @@ You have the possibility to clear these old executions by clicking on the Clear status button in the status banner of your job.

                                  Clear status

                                  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 fc84e264d3..1163eecd9e 100644 --- a/docs/using-qovery/index.html +++ b/docs/using-qovery/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@
                                  Resources
                                    - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/api-integration/index.html b/docs/using-qovery/integration/api-integration/index.html index fcadcdad03..179085e80d 100644 --- a/docs/using-qovery/integration/api-integration/index.html +++ b/docs/using-qovery/integration/api-integration/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@
                                    - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/container-registry/index.html b/docs/using-qovery/integration/container-registry/index.html index 0d5d734214..8e140f20c3 100644 --- a/docs/using-qovery/integration/container-registry/index.html +++ b/docs/using-qovery/integration/container-registry/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                    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 89b2415eb5..d6ea3a20d4 100644 --- a/docs/using-qovery/integration/continuous-integration/circle-ci/index.html +++ b/docs/using-qovery/integration/continuous-integration/circle-ci/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -56,27 +56,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/github-actions/index.html b/docs/using-qovery/integration/continuous-integration/github-actions/index.html index 867bed3e21..dad776119a 100644 --- a/docs/using-qovery/integration/continuous-integration/github-actions/index.html +++ b/docs/using-qovery/integration/continuous-integration/github-actions/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -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 c0404a4056..624648e0a7 100644 --- a/docs/using-qovery/integration/continuous-integration/gitlab-ci/index.html +++ b/docs/using-qovery/integration/continuous-integration/gitlab-ci/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -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 de1e57adf6..bb8bcbfed0 100644 --- a/docs/using-qovery/integration/continuous-integration/index.html +++ b/docs/using-qovery/integration/continuous-integration/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                      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 d9e5b0d8b7..816825e3b0 100644 --- a/docs/using-qovery/integration/continuous-integration/jenkins/index.html +++ b/docs/using-qovery/integration/continuous-integration/jenkins/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -56,27 +56,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/git-repository/index.html b/docs/using-qovery/integration/git-repository/index.html index c6aa7fbf06..b081f8c848 100644 --- a/docs/using-qovery/integration/git-repository/index.html +++ b/docs/using-qovery/integration/git-repository/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                      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 index 64b7141196..cf6fb27e9c 100644 --- a/docs/using-qovery/integration/helm-repository/index.html +++ b/docs/using-qovery/integration/helm-repository/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                        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
                                          - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/index.html b/docs/using-qovery/integration/index.html index 7711256128..1d7c26a16a 100644 --- a/docs/using-qovery/integration/index.html +++ b/docs/using-qovery/integration/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@
                                          Resources
                                            - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/integration/monitoring/datadog/index.html b/docs/using-qovery/integration/monitoring/datadog/index.html index 5864f995ce..bd716aa39c 100644 --- a/docs/using-qovery/integration/monitoring/datadog/index.html +++ b/docs/using-qovery/integration/monitoring/datadog/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -54,27 +54,27 @@ 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 17ee228e98..b4a572b6fa 100644 --- a/docs/using-qovery/integration/monitoring/index.html +++ b/docs/using-qovery/integration/monitoring/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                              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 deploying the helm chart with Qovery

                                              1. Follow this guide to deploy your Helm Chart with Qovery.

                                              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 6b649cf62d..db2563abf0 100644 --- a/docs/using-qovery/integration/monitoring/new-relic/index.html +++ b/docs/using-qovery/integration/monitoring/new-relic/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                              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 deploying the helm chart with Qovery

                                              1. Follow this guide to deploy your NewRelic Helm Chart with Qovery.

                                              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 fab99460d5..68b15a1b42 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 @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                              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 1068374fd8..5af8c34bac 100644 --- a/docs/using-qovery/integration/secret-manager/doppler/index.html +++ b/docs/using-qovery/integration/secret-manager/doppler/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                                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 e7c0313a16..c78caeddb2 100644 --- a/docs/using-qovery/integration/secret-manager/index.html +++ b/docs/using-qovery/integration/secret-manager/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                                  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 deploying the helm chart with Qovery

                                                  1. Follow this guide to deploy your Helm Chart with Qovery.

                                                  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 cbf2540ce8..cc4b4512a7 100644 --- a/docs/using-qovery/integration/slack/index.html +++ b/docs/using-qovery/integration/slack/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                                  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 86b5650bc7..60ed19f758 100644 --- a/docs/using-qovery/integration/terraform/index.html +++ b/docs/using-qovery/integration/terraform/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -54,27 +54,27 @@ 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 bc17eca898..f224def8be 100644 --- a/docs/using-qovery/integration/webhook/index.html +++ b/docs/using-qovery/integration/webhook/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                                  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 63d7119bc3..72715f0502 100644 --- a/docs/using-qovery/interface/cli/index.html +++ b/docs/using-qovery/interface/cli/index.html @@ -24,29 +24,29 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -87,29 +87,29 @@
                                                  qovery log --organization MyOrg --project MyProject --environment MyEnv --application MyApp
                                                  # you will see the log output

                                                  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 237e92f888..5dabb69bbd 100644 --- a/docs/using-qovery/interface/index.html +++ b/docs/using-qovery/interface/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                                  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 07fda94ac4..0804559547 100644 --- a/docs/using-qovery/interface/rest-api/index.html +++ b/docs/using-qovery/interface/rest-api/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                                    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 6d500053c2..d083cdc5d5 100644 --- a/docs/using-qovery/interface/terraform-interface/index.html +++ b/docs/using-qovery/interface/terraform-interface/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@
                                                    - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/interface/web-interface/index.html b/docs/using-qovery/interface/web-interface/index.html index 2b19233f71..f1e994f8fb 100644 --- a/docs/using-qovery/interface/web-interface/index.html +++ b/docs/using-qovery/interface/web-interface/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                                    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 ea50eb32d5..2ed0626277 100644 --- a/docs/using-qovery/maintenance/index.html +++ b/docs/using-qovery/maintenance/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -69,27 +69,27 @@
                                                    echo "[+] Done"

                                                    You will see the following output:

                                                    [+] Ensure there is only one Access Key
                                                    -> Current (future old) key detected: xxx
                                                    [+] Create a new Access Key
                                                    -> Successfully created a new access key: yyy
                                                    [+] Update Qovery credentials
                                                    [+] Deploy the cluster with the new credentials
                                                    [+] Wait for the cluster deployment to be done
                                                    -> 15:04 Waiting for the cluster deployment to be done. Current status: DEPLOYING...
                                                    -> 15:05 Waiting for the cluster deployment to be done. Current status: DEPLOYING...
                                                    -> 15:06 Waiting for the cluster deployment to be done. Current status: DEPLOYING...
                                                    -> 15:07 Waiting for the cluster deployment to be done. Current status: RUNNING...
                                                    [+] Waiting up to 2h to ensure all ongoing deployments are done (Fri Nov 11 03:22:57 PM CET 2022)
                                                    [+] Delete the old Access Key
                                                    [+] Done
                                                    - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/troubleshoot/cluster-troubleshoot/index.html b/docs/using-qovery/troubleshoot/cluster-troubleshoot/index.html index 38b8981b6d..433079ade1 100644 --- a/docs/using-qovery/troubleshoot/cluster-troubleshoot/index.html +++ b/docs/using-qovery/troubleshoot/cluster-troubleshoot/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                                    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/index.html b/docs/using-qovery/troubleshoot/index.html index 85f008ba23..c9276ebfb5 100644 --- a/docs/using-qovery/troubleshoot/index.html +++ b/docs/using-qovery/troubleshoot/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,27 +53,27 @@

                                                    Troubleshoot

                                                    This guide is divided into three sections that will guide you through your troubleshooting depending on your issue:

                                                    • Service Deployment troubleshoot: you will find here the most common deployment errors and their solutions.
                                                    • Service Run troubleshoot: you will find here the most common run errors and their solutions.
                                                    • Cluster troubleshoot: you will find here the error you might find while deploying or updating a cluster.
                                                    Cluster troubleshoot
                                                    Service deployment troubleshoot
                                                    Service run troubleshoot
                                                    Resources
                                                      - + - + - + - + - + - + - + - + - + - + diff --git a/docs/using-qovery/troubleshoot/service-deployment-troubleshoot/index.html b/docs/using-qovery/troubleshoot/service-deployment-troubleshoot/index.html index 9128870a79..d7046e6b8d 100644 --- a/docs/using-qovery/troubleshoot/service-deployment-troubleshoot/index.html +++ b/docs/using-qovery/troubleshoot/service-deployment-troubleshoot/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -56,27 +56,27 @@ 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

                                                      Database

                                                      SnapshotQuotaExceeded - while deleting a managed DB

                                                      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/service-run-troubleshoot/index.html b/docs/using-qovery/troubleshoot/service-run-troubleshoot/index.html index ef16d3dbf4..d9112ab1e1 100644 --- a/docs/using-qovery/troubleshoot/service-run-troubleshoot/index.html +++ b/docs/using-qovery/troubleshoot/service-run-troubleshoot/index.html @@ -24,27 +24,27 @@ - + - + - + - + - + - + - + - + - + - + @@ -54,27 +54,27 @@ If you don't make a copy, doing this procedure directly on the PRODUCTION application will lead to a downtime in your service. Be sure of what you're doing before going ahead!

                                                      Your app is crashing very quickly, here is how to keep the full control of your container:

                                                      1. Temporary delete the application port from your application configuration. This to avoid Kubernetes to restart the container when the port is not open.

                                                      2. Into your Dockerfile, comment your EXEC or ENTRYPOINT and add a way to make your container sleep. For example:

                                                        #CMD ["npm", "run", "start"]
                                                        CMD ["tail", "-f", "/dev/null"]

                                                        Commit and push your changes to trigger a new deployment (trigger it manually from the Qovery console if it's not the case).

                                                      3. Once the deployment done, you can use qovery shell command to connect to your container and debug.

                                                      I can't access my application logs

                                                      If you are deploying a helm service, to get all the Qovery features (access your container logs, apply the stop/restart actions, display the pod status in the overview page), make sure to create an override and assign the macros qovery.labels.service and qovery.annotations.service to the labels and annotations of any deployed Pods/Deployments/Services/Jobs.

                                                      Override example:

                                                      commonLabels:
                                                      mylabel: "test"
                                                      qovery.labels.service
                                                      annotations:
                                                      qovery.annotations.service

                                                      These macros will be automatically replaced by Qovery during the deployment phase.

                                                      - + - + - + - + - + - + - + - + - + - + diff --git a/e06f2af5.8b12fef7.js b/e06f2af5.08fd2949.js similarity index 93% rename from e06f2af5.8b12fef7.js rename to e06f2af5.08fd2949.js index 863ef42635..92a965beca 100644 --- a/e06f2af5.8b12fef7.js +++ b/e06f2af5.08fd2949.js @@ -1,2 +1,2 @@ -/*! For license information please see e06f2af5.8b12fef7.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[263],{415: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(449)),a=n(456),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},447: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"\n logGroupName: "/aws/eks/fluentbit-/logs"\n logRetentionDays: 7\n\nenv:\n - name: "AWS_ACCESS_KEY_ID"\n value: qovery.env.AWS_ACCESS_KEY\n - name: "AWS_SECRET_ACCESS_KEY"\n value: qovery.env.AWS_SECRET_ACCESS_KEY\n\nfirehose:\n enabled: false\n\nkinesis:\n enabled: false\n\nelasticsearch:\n enabled: false\n')),Object(o.b)("p",null,"You can take a look at additional configuration options on the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://artifacthub.io/packages/helm/aws/aws-for-fluent-bit"}),"AWS provided chart")," "),Object(o.b)("p",null,"Now get to the last step and just ",Object(o.b)("inlineCode",{parentName:"p"},"Create")," the service on Qovery."),Object(o.b)("h3",{id:"store-the-aws-secrets-as-qovery-secrets"},"Store the AWS Secrets as Qovery secrets"),Object(o.b)("p",null,"In the previous step we have assigned the macro ",Object(o.b)("inlineCode",{parentName:"p"},"qovery.env.qovery.env.AWS_ACCESS_KEY")," and ",Object(o.b)("inlineCode",{parentName:"p"},"qovery.env.AWS_SECRET_ACCESS_KEY")," to the AWS secrets. In this step we will create these secrets within the Qovery console."),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Open the service overview of the created Datadog service"),Object(o.b)("li",{parentName:"ul"},"Enter the ",Object(o.b)("inlineCode",{parentName:"li"},"Variables")," section"),Object(o.b)("li",{parentName:"ul"},"Add a new Variable with:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Variable = AWS_SECRET_ACCESS_KEY"),Object(o.b)("li",{parentName:"ul"},"Value = "),Object(o.b)("li",{parentName:"ul"},"Scope = Service (so that it is accessible only to this service)"),Object(o.b)("li",{parentName:"ul"},"Secret variable \u2714\ufe0f"))),Object(o.b)("li",{parentName:"ul"},"Add a new Variable with:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Variable = AWS_ACCESS_KEY"),Object(o.b)("li",{parentName:"ul"},"Value = "),Object(o.b)("li",{parentName:"ul"},"Scope = Service (so that it is accessible only to this service)"),Object(o.b)("li",{parentName:"ul"},"Secret variable \u2714\ufe0f")))),Object(o.b)("p",null,"If you need more information on how to manage your environment variables, have a look at ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"this documentation")),Object(o.b)("h3",{id:"deploy-your-chart"},"Deploy your chart"),Object(o.b)("p",null,"Open the ",Object(o.b)("inlineCode",{parentName:"p"},"Play")," button and trigger the deployment of your chart."),Object(o.b)("h2",{id:"cloudwatch-usage"},"Cloudwatch usage"),Object(o.b)("p",null,"You can now use Cloudwatch to look at your logs. Connect to Cloudwatch, go into the ",Object(o.b)("inlineCode",{parentName:"p"},"Logs insight")," section, then you can perform queries:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/aws-cloudwatch/cloudwatch-search.png",alt:"cloudwatch search"})),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Select the fluent-bit group of logs"),Object(o.b)("li",{parentName:"ol"},"Create a query (",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html"}),"syntax examples"),")"),Object(o.b)("li",{parentName:"ol"},"Run your query"),Object(o.b)("li",{parentName:"ol"},"See the result and expand to filter on other elements")))}b.isMDXComponent=!0},447: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):l({},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,i=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),b=u(n),d=a,m=b["".concat(i,".").concat(d)]||b[d]||p[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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(458),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(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(i.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}))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(454),i=n(447),l=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,s=e.size,u=e.target,b=e.to,p=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 u?r.a.createElement("a",{href:b,target:u,className:p},d):r.a.createElement(o.a,{to:b,className:p},d)}},458: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.52b61b17.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[266],{418: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 b}));var a=n(1),r=n(9),o=(n(0),n(451)),i=(n(459),n(450)),l=(n(455),{last_modified_on:"2024-05-09",$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}),c={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:"5 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:"Import your environment variables with the Qovery CLI",permalink:"/guides/tutorial/import-your-environment-variables-with-the-qovery-cli"},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:"Add the AWS EKS helm repository",id:"add-the-aws-eks-helm-repository",children:[]},{value:"Create and deploy the helm chart within Qovery",id:"create-and-deploy-the-helm-chart-within-qovery",children:[]},{value:"Store the AWS Secrets as Qovery secrets",id:"store-the-aws-secrets-as-qovery-secrets",children:[]},{value:"Deploy your chart",id:"deploy-your-chart",children:[]}]},{value:"Cloudwatch usage",id:"cloudwatch-usage",children:[]}],u={rightToc:s};function b(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,"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(o.b)("p",null,"Qovery implementation is based on ",Object(o.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(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"Why Qovery does not provides current Loki access?"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"As mentioned Loki is not a full-text search and results may not reflect what you are looking for."),Object(o.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(o.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(o.b)("a",Object(a.a)({parentName:"p"},{href:"/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/"}),"Datadog integration"),"."),Object(o.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(o.b)("h2",{id:"aws-permissions-for-cloudwatch"},"AWS permissions for Cloudwatch"),Object(o.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(o.b)("p",null,"On IAM create a policy with the following permissions, and name this policy ",Object(o.b)("inlineCode",{parentName:"p"},"fluent-bit-write-policy"),":"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/aws-cloudwatch/fluent-bit-policy-content.png",alt:"policy content"})),Object(o.b)("pre",null,Object(o.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(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/aws-cloudwatch/fluent-bit-policy-create.png",alt:"policy create"})),Object(o.b)(i.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"You can enforce this policy by cluster if you need, by updating the ",Object(o.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(o.b)("p",null,"Once done, let's create a user and attach the policy to it:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/aws-cloudwatch/fluent-bit-user-create.png",alt:"User create"})),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/aws-cloudwatch/fluent-bit-cloudwatch-permissions.png",alt:"User permissions"})),Object(o.b)("p",null,"Finish the user creation and keep credentials for the coming section."),Object(o.b)("h2",{id:"helm"},"Helm"),Object(o.b)("p",null,"We will use ",Object(o.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 and deploy it with Qovery."),Object(o.b)("h3",{id:"add-the-aws-eks-helm-repository"},"Add the AWS EKS helm repository"),Object(o.b)("p",null,"Add the AWS EKS helm repository in your Qovery settings by following ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/helm-repository/"}),"this documentation")),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Repository name: ",Object(o.b)("inlineCode",{parentName:"li"},"eks")),Object(o.b)("li",{parentName:"ul"},"Kind: ",Object(o.b)("inlineCode",{parentName:"li"},"HTTPS")),Object(o.b)("li",{parentName:"ul"},"Repository URL: ",Object(o.b)("inlineCode",{parentName:"li"},"https://aws.github.io/eks-charts"))),Object(o.b)("h3",{id:"create-and-deploy-the-helm-chart-within-qovery"},"Create and deploy the helm chart within Qovery"),Object(o.b)("p",null,"Create a helm service in the Qovery environment of your choice (preferrably within a dedicated Tooling project) by following ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/"}),"this documentation")," and these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"General:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Application name: ",Object(o.b)("inlineCode",{parentName:"li"},"fluent-bit")),Object(o.b)("li",{parentName:"ul"},"Source:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Helm source: ",Object(o.b)("inlineCode",{parentName:"li"},"Helm repository")),Object(o.b)("li",{parentName:"ul"},"Repository: ",Object(o.b)("inlineCode",{parentName:"li"},"eks")," (the name given during the AWS EKS helm repository added in the previous step)"),Object(o.b)("li",{parentName:"ul"},"Chart name: ",Object(o.b)("inlineCode",{parentName:"li"},"aws-for-fluent-bit")),Object(o.b)("li",{parentName:"ul"},"Version: ",Object(o.b)("inlineCode",{parentName:"li"},"0.1.21")," (this is the version we used for this setup, update it based on the chosen version)"),Object(o.b)("li",{parentName:"ul"},"Allow cluster-wide resources \u2714\ufe0f"))))),Object(o.b)("li",{parentName:"ul"},"Values",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Values override as file:"),Object(o.b)("li",{parentName:"ul"},"File source: ",Object(o.b)("inlineCode",{parentName:"li"},"Raw YAML")),Object(o.b)("li",{parentName:"ul"},"Raw YAML:")))),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),'priorityClassName: system-node-critical\n\ncloudWatch:\n enabled: true\n region: ""\n logGroupName: "/aws/eks/fluentbit-/logs"\n logRetentionDays: 7\n\nenv:\n - name: "AWS_ACCESS_KEY_ID"\n value: qovery.env.AWS_ACCESS_KEY\n - name: "AWS_SECRET_ACCESS_KEY"\n value: qovery.env.AWS_SECRET_ACCESS_KEY\n\nfirehose:\n enabled: false\n\nkinesis:\n enabled: false\n\nelasticsearch:\n enabled: false\n')),Object(o.b)("p",null,"You can take a look at additional configuration options on the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://artifacthub.io/packages/helm/aws/aws-for-fluent-bit"}),"AWS provided chart")," "),Object(o.b)("p",null,"Now get to the last step and just ",Object(o.b)("inlineCode",{parentName:"p"},"Create")," the service on Qovery."),Object(o.b)("h3",{id:"store-the-aws-secrets-as-qovery-secrets"},"Store the AWS Secrets as Qovery secrets"),Object(o.b)("p",null,"In the previous step we have assigned the macro ",Object(o.b)("inlineCode",{parentName:"p"},"qovery.env.qovery.env.AWS_ACCESS_KEY")," and ",Object(o.b)("inlineCode",{parentName:"p"},"qovery.env.AWS_SECRET_ACCESS_KEY")," to the AWS secrets. In this step we will create these secrets within the Qovery console."),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Open the service overview of the created Datadog service"),Object(o.b)("li",{parentName:"ul"},"Enter the ",Object(o.b)("inlineCode",{parentName:"li"},"Variables")," section"),Object(o.b)("li",{parentName:"ul"},"Add a new Variable with:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Variable = AWS_SECRET_ACCESS_KEY"),Object(o.b)("li",{parentName:"ul"},"Value = "),Object(o.b)("li",{parentName:"ul"},"Scope = Service (so that it is accessible only to this service)"),Object(o.b)("li",{parentName:"ul"},"Secret variable \u2714\ufe0f"))),Object(o.b)("li",{parentName:"ul"},"Add a new Variable with:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Variable = AWS_ACCESS_KEY"),Object(o.b)("li",{parentName:"ul"},"Value = "),Object(o.b)("li",{parentName:"ul"},"Scope = Service (so that it is accessible only to this service)"),Object(o.b)("li",{parentName:"ul"},"Secret variable \u2714\ufe0f")))),Object(o.b)("p",null,"If you need more information on how to manage your environment variables, have a look at ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/environment-variable/"}),"this documentation")),Object(o.b)("h3",{id:"deploy-your-chart"},"Deploy your chart"),Object(o.b)("p",null,"Open the ",Object(o.b)("inlineCode",{parentName:"p"},"Play")," button and trigger the deployment of your chart."),Object(o.b)("h2",{id:"cloudwatch-usage"},"Cloudwatch usage"),Object(o.b)("p",null,"You can now use Cloudwatch to look at your logs. Connect to Cloudwatch, go into the ",Object(o.b)("inlineCode",{parentName:"p"},"Logs insight")," section, then you can perform queries:"),Object(o.b)("p",{Valign:"center"},Object(o.b)("img",{src:"/img/aws-cloudwatch/cloudwatch-search.png",alt:"cloudwatch search"})),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Select the fluent-bit group of logs"),Object(o.b)("li",{parentName:"ol"},"Create a query (",Object(o.b)("a",Object(a.a)({parentName:"li"},{href:"https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html"}),"syntax examples"),")"),Object(o.b)("li",{parentName:"ol"},"Run your query"),Object(o.b)("li",{parentName:"ol"},"See the result and expand to filter on other elements")))}b.isMDXComponent=!0},449: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):l({},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,i=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),b=u(n),d=a,m=b["".concat(i,".").concat(d)]||b[d]||p[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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(460),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(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(i.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}))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(456),i=n(449),l=n.n(i);n(134);t.a=function(e){var t=e.children,n=e.className,a=e.badge,i=e.leftIcon,c=e.rightIcon,s=e.size,u=e.target,b=e.to,p=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 u?r.a.createElement("a",{href:b,target:u,className:p},d):r.a.createElement(o.a,{to:b,className:p},d)}},460: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/e1e1580b.105fa7a3.js.LICENSE.txt b/e1becc8e.52b61b17.js.LICENSE.txt similarity index 100% rename from e1e1580b.105fa7a3.js.LICENSE.txt rename to e1becc8e.52b61b17.js.LICENSE.txt diff --git a/e1e0a511.fbdcf0a7.js b/e1e0a511.47bbf0ae.js similarity index 90% rename from e1e0a511.fbdcf0a7.js rename to e1e0a511.47bbf0ae.js index ad844d0285..9b519e6c03 100644 --- a/e1e0a511.fbdcf0a7.js +++ b/e1e0a511.47bbf0ae.js @@ -1,2 +1,2 @@ -/*! For license information please see e1e0a511.fbdcf0a7.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[265],{417: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),i=r(9),o=(r(0),r(449)),a=r(448),c={last_modified_on:"2024-01-03",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 deploying the helm chart with Qovery",id:"by-deploying-the-helm-chart-with-qovery",children:[]},{value:"By using kubectl",id:"by-using-kubectl",children:[]}]}],s={rightToc:u};function p(e){var t=e.components,r=Object(i.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(o.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(o.b)("h2",{id:"install-newrelic"},"Install NewRelic"),Object(o.b)("p",null,"To install NewRelic on Qovery, you have 2 choices:"),Object(o.b)("h3",{id:"by-deploying-the-helm-chart-with-qovery"},"By deploying the helm chart with Qovery"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Follow ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/helm/"}),"this guide")," to deploy your NewRelic Helm Chart with Qovery.")),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"},"Use ",Object(o.b)("inlineCode",{parentName:"li"},"helm")," to ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/newrelic/helm-charts"}),"install NewRelic"),".")),Object(o.b)(a.a,{type:"info",mdxType:"Alert"},Object(o.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},447:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function i(){for(var e=[],t=0;t=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var u=i.a.createContext({}),s=function(e){var t=i.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 i.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},f=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=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]||o;return r?i.a.createElement(y,c({ref:t},u,{components:r})):i.a.createElement(y,c({ref:t},u))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,a=new Array(o);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:i(l,r);u>c;)t[c++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see e1e0a511.47bbf0ae.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[267],{419: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),i=r(9),o=(r(0),r(451)),a=r(450),c={last_modified_on:"2024-01-03",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 deploying the helm chart with Qovery",id:"by-deploying-the-helm-chart-with-qovery",children:[]},{value:"By using kubectl",id:"by-using-kubectl",children:[]}]}],s={rightToc:u};function p(e){var t=e.components,r=Object(i.a)(e,["components"]);return Object(o.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(o.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(o.b)("h2",{id:"install-newrelic"},"Install NewRelic"),Object(o.b)("p",null,"To install NewRelic on Qovery, you have 2 choices:"),Object(o.b)("h3",{id:"by-deploying-the-helm-chart-with-qovery"},"By deploying the helm chart with Qovery"),Object(o.b)("ol",null,Object(o.b)("li",{parentName:"ol"},"Follow ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"/docs/using-qovery/configuration/helm/"}),"this guide")," to deploy your NewRelic Helm Chart with Qovery.")),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"},"Use ",Object(o.b)("inlineCode",{parentName:"li"},"helm")," to ",Object(o.b)("a",Object(n.a)({parentName:"li"},{href:"https://github.com/newrelic/helm-charts"}),"install NewRelic"),".")),Object(o.b)(a.a,{type:"info",mdxType:"Alert"},Object(o.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},449:function(e,t,r){var n;!function(){"use strict";var r={}.hasOwnProperty;function i(){for(var e=[],t=0;t=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var u=i.a.createContext({}),s=function(e){var t=i.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 i.a.createElement(u.Provider,{value:t},e.children)},b={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},f=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=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]||o;return r?i.a.createElement(y,c({ref:t},u,{components:r})):i.a.createElement(y,c({ref:t},u))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,a=new Array(o);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:i(l,r);u>c;)t[c++]=e;return t}}}]); \ No newline at end of file diff --git a/e3c664e0.046939c5.js.LICENSE.txt b/e1e0a511.47bbf0ae.js.LICENSE.txt similarity index 100% rename from e3c664e0.046939c5.js.LICENSE.txt rename to e1e0a511.47bbf0ae.js.LICENSE.txt diff --git a/e1e1580b.105fa7a3.js b/e1e1580b.a735d553.js similarity index 91% rename from e1e1580b.105fa7a3.js rename to e1e1580b.a735d553.js index f097553f5f..6e4fda84a0 100644 --- a/e1e1580b.105fa7a3.js +++ b/e1e1580b.a735d553.js @@ -1,2 +1,2 @@ -/*! For license information please see e1e1580b.105fa7a3.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[266],{418: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 m}));var r=n(1),a=n(9),o=(n(0),n(449)),i=n(456),c=n(448),l=n(453),u=(n(457),{last_modified_on:"2024-04-10",$schema:"/.meta/.schemas/guides.json",title:"Monitor and reduce Kubernetes spend with Kubecost",description:"How to deploy Kubecost with Qovery",author_github:"https://github.com/jul-dan",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:"Monitor and reduce Kubernetes spend with Kubecost",description:"How to deploy Kubecost with Qovery",permalink:"/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost",readingTime:"3 min read",source:"@site/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Monitor and reduce Kubernetes spend with Kubecost",truncated:!1,prevItem:{title:"Migration",permalink:"/guides/advanced/migration"},nextItem:{title:"Monitoring",permalink:"/guides/advanced/monitoring"}},b=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],p={rightToc:b};function m(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)(l.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)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"In this tutorial, we will install Kubecost on a Qovery cluster to monitor the Kubernetes costs"),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"add-the-kubecost-helm-repository"},"Add the Kubecost helm repository"),Object(o.b)("p",null,"Add the Kubecost helm repository in your Qovery settings by following ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/helm-repository/"}),"this documentation")," with these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Repository name: ",Object(o.b)("inlineCode",{parentName:"li"},"Kubecost")),Object(o.b)("li",{parentName:"ul"},"Kind: ",Object(o.b)("inlineCode",{parentName:"li"},"HTTPS")),Object(o.b)("li",{parentName:"ul"},"Repository URL: ",Object(o.b)("inlineCode",{parentName:"li"},"https://kubecost.github.io/cost-analyzer/")))),Object(o.b)("li",null,Object(o.b)("h4",{id:"deploy-the-kubecost-helm-chart"},"Deploy the Kubecost helm chart"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If have a Kubecost token, first create a Qovery environment variable: "),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"variable: ",Object(o.b)("inlineCode",{parentName:"li"},"KUBECOST_TOKEN")),Object(o.b)("li",{parentName:"ul"},"value: ",Object(o.b)("inlineCode",{parentName:"li"},"")),Object(o.b)("li",{parentName:"ul"},"scope: ",Object(o.b)("inlineCode",{parentName:"li"},"Environment")),Object(o.b)("li",{parentName:"ul"},"Secret variable \u2714\ufe0f"))),Object(o.b)("p",null,"Deploy the Kubecost helm chart in your Qovery environment by following ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/"}),"this documentation")," with these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"General:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Application name: ",Object(o.b)("inlineCode",{parentName:"li"},"Kubecost")),Object(o.b)("li",{parentName:"ul"},"Source:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Helm source: ",Object(o.b)("inlineCode",{parentName:"li"},"Helm repository")),Object(o.b)("li",{parentName:"ul"},"Repository: ",Object(o.b)("inlineCode",{parentName:"li"},"Kubecost")," (the name given during the kubecost helm repository added in the previous step)"),Object(o.b)("li",{parentName:"ul"},"Chart name: ",Object(o.b)("inlineCode",{parentName:"li"},"cost-analyzer")),Object(o.b)("li",{parentName:"ul"},"Version: ",Object(o.b)("inlineCode",{parentName:"li"},"1.108.0")," (this guide works with the version 1.108.0 and that needs to be adapted if you use another version)"))),Object(o.b)("li",{parentName:"ul"},"Allow cluster-wide resources \u2714\ufe0f"))),Object(o.b)("li",{parentName:"ul"},"Values",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Values override as file:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"File source: ",Object(o.b)("inlineCode",{parentName:"li"},"Raw YAML")),Object(o.b)("li",{parentName:"ul"},"Raw YAML:")))))),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-yaml"}),"kubecostToken: qovery.env.KUBECOST_TOKEN #Used only if you have a Kubecost Token\n\n")),Object(o.b)("p",null,"Then click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create and Deploy"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"expose-kubecost"},"Expose Kubecost"),Object(o.b)("p",null,"Check the cost-analyzer service name in the deployment logs, example: ",Object(o.b)("inlineCode",{parentName:"p"},"helm-z325f0565-kubecost-cost-analyzer")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/monitor-and-reduce-kubernetes-spend-with-kubecost/service-name.png",alt:"Service name"})),Object(o.b)("p",null,"Go in your helm chart settings under the ",Object(o.b)("inlineCode",{parentName:"p"},"Networking")," section and add a new port by clicking on ",Object(o.b)("inlineCode",{parentName:"p"},"Add port"),", and set these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Service name: ",Object(o.b)("inlineCode",{parentName:"li"},"helm-z325f0565-kubecost-cost-analyzer")," (the service name taken from the deployment logs)"),Object(o.b)("li",{parentName:"ul"},"Service port: ",Object(o.b)("inlineCode",{parentName:"li"},"9090")),Object(o.b)("li",{parentName:"ul"},"Select protocol: ",Object(o.b)("inlineCode",{parentName:"li"},"HTTP")),Object(o.b)("li",{parentName:"ul"},"Port name: You can customize it or let the default port name.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/monitor-and-reduce-kubernetes-spend-with-kubecost/add-port.png",alt:"Add port"})),Object(o.b)("p",null,"Then click on Create and redeploy your helm in Qovery."),Object(o.b)("p",null,"A URL will be generated to access the Kubecost frontend application:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/monitor-and-reduce-kubernetes-spend-with-kubecost/link.png",alt:"Link"}))))),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"You now have Kubecost 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(r.a)({parentName:"p"},{href:"https://docs.kubecost.com/#getting-started"}),"https://docs.kubecost.com/#getting-started"),"."))}m.isMDXComponent=!0},447: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},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)}},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"]),b=s(n),m=r,d=b["".concat(i,".").concat(m)]||b[m]||p[m]||o;return n?a.a.createElement(d,c({ref:t},u,{components:n})):a.a.createElement(d,c({ref:t},u))}));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 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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},454:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(458),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,b=Object(c.a)(s),p=Object(a.useRef)(!1),m=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!m&&b&&window.docusaurus.prefetch(s),function(){m&&t&&t.disconnect()}}),[s,m,b]),s&&b?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var n,r;m&&e&&b&&(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}))}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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),b=s[0],p=s[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: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"),"."))}},457:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(454),i=n(447),c=n.n(i);n(134);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,b=e.to,p=c()("jump-to","jump-to--"+u,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 s?a.a.createElement("a",{href:b,target:s,className:p},m):a.a.createElement(o.a,{to:b,className:p},m)}},458:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},459: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 e1e1580b.a735d553.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[268],{420: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 m}));var r=n(1),a=n(9),o=(n(0),n(451)),i=n(458),c=n(450),l=n(455),u=(n(459),{last_modified_on:"2024-04-10",$schema:"/.meta/.schemas/guides.json",title:"Monitor and reduce Kubernetes spend with Kubecost",description:"How to deploy Kubecost with Qovery",author_github:"https://github.com/jul-dan",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:"Monitor and reduce Kubernetes spend with Kubecost",description:"How to deploy Kubecost with Qovery",permalink:"/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost",readingTime:"3 min read",source:"@site/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost.md",tags:[{label:"type: tutorial",permalink:"/guides/tags/type-tutorial"},{label:"technology: qovery",permalink:"/guides/tags/technology-qovery"}],title:"Monitor and reduce Kubernetes spend with Kubecost",truncated:!1,prevItem:{title:"Migration",permalink:"/guides/advanced/migration"},nextItem:{title:"Monitoring",permalink:"/guides/advanced/monitoring"}},b=[{value:"Goal",id:"goal",children:[]},{value:"Conclusion",id:"conclusion",children:[]}],p={rightToc:b};function m(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)(l.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)("h2",{id:"goal"},"Goal"),Object(o.b)("p",null,"In this tutorial, we will install Kubecost on a Qovery cluster to monitor the Kubernetes costs"),Object(o.b)(i.a,{headingDepth:3,mdxType:"Steps"},Object(o.b)("ol",null,Object(o.b)("li",null,Object(o.b)("h4",{id:"add-the-kubecost-helm-repository"},"Add the Kubecost helm repository"),Object(o.b)("p",null,"Add the Kubecost helm repository in your Qovery settings by following ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/organization/helm-repository/"}),"this documentation")," with these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Repository name: ",Object(o.b)("inlineCode",{parentName:"li"},"Kubecost")),Object(o.b)("li",{parentName:"ul"},"Kind: ",Object(o.b)("inlineCode",{parentName:"li"},"HTTPS")),Object(o.b)("li",{parentName:"ul"},"Repository URL: ",Object(o.b)("inlineCode",{parentName:"li"},"https://kubecost.github.io/cost-analyzer/")))),Object(o.b)("li",null,Object(o.b)("h4",{id:"deploy-the-kubecost-helm-chart"},"Deploy the Kubecost helm chart"),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.b)("p",null,"If have a Kubecost token, first create a Qovery environment variable: "),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"variable: ",Object(o.b)("inlineCode",{parentName:"li"},"KUBECOST_TOKEN")),Object(o.b)("li",{parentName:"ul"},"value: ",Object(o.b)("inlineCode",{parentName:"li"},"")),Object(o.b)("li",{parentName:"ul"},"scope: ",Object(o.b)("inlineCode",{parentName:"li"},"Environment")),Object(o.b)("li",{parentName:"ul"},"Secret variable \u2714\ufe0f"))),Object(o.b)("p",null,"Deploy the Kubecost helm chart in your Qovery environment by following ",Object(o.b)("a",Object(r.a)({parentName:"p"},{href:"/docs/using-qovery/configuration/helm/"}),"this documentation")," with these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"General:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Application name: ",Object(o.b)("inlineCode",{parentName:"li"},"Kubecost")),Object(o.b)("li",{parentName:"ul"},"Source:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Helm source: ",Object(o.b)("inlineCode",{parentName:"li"},"Helm repository")),Object(o.b)("li",{parentName:"ul"},"Repository: ",Object(o.b)("inlineCode",{parentName:"li"},"Kubecost")," (the name given during the kubecost helm repository added in the previous step)"),Object(o.b)("li",{parentName:"ul"},"Chart name: ",Object(o.b)("inlineCode",{parentName:"li"},"cost-analyzer")),Object(o.b)("li",{parentName:"ul"},"Version: ",Object(o.b)("inlineCode",{parentName:"li"},"1.108.0")," (this guide works with the version 1.108.0 and that needs to be adapted if you use another version)"))),Object(o.b)("li",{parentName:"ul"},"Allow cluster-wide resources \u2714\ufe0f"))),Object(o.b)("li",{parentName:"ul"},"Values",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"Values override as file:",Object(o.b)("ul",{parentName:"li"},Object(o.b)("li",{parentName:"ul"},"File source: ",Object(o.b)("inlineCode",{parentName:"li"},"Raw YAML")),Object(o.b)("li",{parentName:"ul"},"Raw YAML:")))))),Object(o.b)("pre",null,Object(o.b)("code",Object(r.a)({parentName:"pre"},{className:"language-yaml"}),"kubecostToken: qovery.env.KUBECOST_TOKEN #Used only if you have a Kubecost Token\n\n")),Object(o.b)("p",null,"Then click on ",Object(o.b)("inlineCode",{parentName:"p"},"Create and Deploy"))),Object(o.b)("li",null,Object(o.b)("h4",{id:"expose-kubecost"},"Expose Kubecost"),Object(o.b)("p",null,"Check the cost-analyzer service name in the deployment logs, example: ",Object(o.b)("inlineCode",{parentName:"p"},"helm-z325f0565-kubecost-cost-analyzer")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/monitor-and-reduce-kubernetes-spend-with-kubecost/service-name.png",alt:"Service name"})),Object(o.b)("p",null,"Go in your helm chart settings under the ",Object(o.b)("inlineCode",{parentName:"p"},"Networking")," section and add a new port by clicking on ",Object(o.b)("inlineCode",{parentName:"p"},"Add port"),", and set these values:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"Service name: ",Object(o.b)("inlineCode",{parentName:"li"},"helm-z325f0565-kubecost-cost-analyzer")," (the service name taken from the deployment logs)"),Object(o.b)("li",{parentName:"ul"},"Service port: ",Object(o.b)("inlineCode",{parentName:"li"},"9090")),Object(o.b)("li",{parentName:"ul"},"Select protocol: ",Object(o.b)("inlineCode",{parentName:"li"},"HTTP")),Object(o.b)("li",{parentName:"ul"},"Port name: You can customize it or let the default port name.")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/monitor-and-reduce-kubernetes-spend-with-kubecost/add-port.png",alt:"Add port"})),Object(o.b)("p",null,"Then click on Create and redeploy your helm in Qovery."),Object(o.b)("p",null,"A URL will be generated to access the Kubecost frontend application:"),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/monitor-and-reduce-kubernetes-spend-with-kubecost/link.png",alt:"Link"}))))),Object(o.b)("h2",{id:"conclusion"},"Conclusion"),Object(o.b)("p",null,"You now have Kubecost 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(r.a)({parentName:"p"},{href:"https://docs.kubecost.com/#getting-started"}),"https://docs.kubecost.com/#getting-started"),"."))}m.isMDXComponent=!0},449: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},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)}},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"]),b=s(n),m=r,d=b["".concat(i,".").concat(m)]||b[m]||p[m]||o;return n?a.a.createElement(d,c({ref:t},u,{components:n})):a.a.createElement(d,c({ref:t},u))}));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 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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},456:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(460),l=n(20),u=n.n(l);t.a=function(e){var t,n=e.to,l=e.href,s=n||l,b=Object(c.a)(s),p=Object(a.useRef)(!1),m=u.a.canUseIntersectionObserver;return Object(a.useEffect)((function(){return!m&&b&&window.docusaurus.prefetch(s),function(){m&&t&&t.disconnect()}}),[s,m,b]),s&&b?o.a.createElement(i.b,Object(r.a)({},e,{onMouseEnter:function(){p.current||(window.docusaurus.preload(s),p.current=!0)},innerRef:function(e){var n,r;m&&e&&b&&(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}))}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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),b=s[0],p=s[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: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"),"."))}},459:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(456),i=n(449),c=n.n(i);n(134);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,b=e.to,p=c()("jump-to","jump-to--"+u,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 s?a.a.createElement("a",{href:b,target:s,className:p},m):a.a.createElement(o.a,{to:b,className:p},m)}},460:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},461: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/e4310ee0.3e9005cc.js.LICENSE.txt b/e1e1580b.a735d553.js.LICENSE.txt similarity index 100% rename from e4310ee0.3e9005cc.js.LICENSE.txt rename to e1e1580b.a735d553.js.LICENSE.txt diff --git a/e3c664e0.046939c5.js b/e3c664e0.dd6d1fd5.js similarity index 94% rename from e3c664e0.046939c5.js rename to e3c664e0.dd6d1fd5.js index 3a2fd4b096..99933ca1ab 100644 --- a/e3c664e0.046939c5.js +++ b/e3c664e0.dd6d1fd5.js @@ -1,2 +1,2 @@ -/*! For license information please see e3c664e0.046939c5.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[267],{419: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),o=(n(0),n(449)),c=(n(457),n(448)),i=(n(453),{last_modified_on:"2024-07-03",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:"Clear old job executions",id:"clear-old-job-executions",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(o.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"From any environment window on your ",Object(o.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(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deployment/run_deployment_statuses.png",alt:"Statuses"})),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}),"1"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"The dot in the service tab shows the environment running status. ",Object(o.b)("br",null)," For more information, see the Environment Statuses section below.")),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}),"The dot in the deployment tab shows the environment deployment status. ",Object(o.b)("br",null)," For more information, see the Deployment Statuses section below.")),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}),'The label in the column "Service status" represents the running status of the service. ',Object(o.b)("br",null)," For more information, see Service Statuses section below.")),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}),'The label in the column "Last deployment" represents the status of the latest deployment of the service. ',Object(o.b)("br",null)," For more information, see Deployment Statuses section below.")))),Object(o.b)("h2",{id:"running-statuses"},"Running Statuses"),Object(o.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(o.b)("h2",{id:"environment-statuses"},"Environment Statuses"),Object(o.b)("p",null,"When you access an environment on your ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),", you can check its status in real-time."),Object(o.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(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}),"Status"),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}),"STOPPED ",Object(o.b)("em",{parentName:"td"},"(Gray dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All the services are stopped.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STARTING ",Object(o.b)("em",{parentName:"td"},"(Loading Icon)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 service is starting.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STOPPING ",Object(o.b)("em",{parentName:"td"},"(Loading Icon)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 service is stopping.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"RUNNING ",Object(o.b)("em",{parentName:"td"},"(Green dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All services are running correctly.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ERROR ",Object(o.b)("em",{parentName:"td"},"(Red dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All services are in error status.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"WARNING ",Object(o.b)("em",{parentName:"td"},"(Orange dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 service is in error status (but not all of them).")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"COMPLETED ",Object(o.b)("em",{parentName:"td"},"(Green dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"The job execution has completed (only for cronjob and lifecycle jobs).")))),Object(o.b)("h2",{id:"service-statuses"},"Service Statuses"),Object(o.b)("p",null,"When you access an environment on your ",Object(o.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(o.b)("p",null,"Here are all the possible service statuses:"),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}),"Status"),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}),"STOPPED ",Object(o.b)("em",{parentName:"td"},"(Gray dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All the application instances are stopped.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STARTING ",Object(o.b)("em",{parentName:"td"},"(Loading Icon)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 application instance is starting.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STOPPING ",Object(o.b)("em",{parentName:"td"},"(Loading Icon)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 application instance is stopping.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"RUNNING ",Object(o.b)("em",{parentName:"td"},"(Green dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All application instances are running correctly.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ERROR ",Object(o.b)("em",{parentName:"td"},"(Red dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All application instances are in error status.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"WARNING ",Object(o.b)("em",{parentName:"td"},"(Orange dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.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(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Completed ",Object(o.b)("em",{parentName:"td"},"(Green dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("em",{parentName:"td"},"(Valid for Lifecycle and Cronjob only)")," The job was correctly executed.")))),Object(o.b)("p",null,"The service status is computed based on the status of each ",Object(o.b)("inlineCode",{parentName:"p"},"Kubernetes pod")," deployed for this application."),Object(o.b)("h3",{id:"pod-status-application-instances"},"Pod status (Application instances)"),Object(o.b)("p",null,"You can check on the ",Object(o.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(o.b)("p",null,"Within this page you will have a view of:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"the number of running instances of your application"),Object(o.b)("li",{parentName:"ul"},"the status of each instance"),Object(o.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(o.b)("p",null,"By clicking on ",Object(o.b)("inlineCode",{parentName:"p"},"Logs"),", you will be redirected to the service logs specifically filtered for this pod."),Object(o.b)("h3",{id:"clear-old-job-executions"},"Clear old job executions"),Object(o.b)("p",null,"If you have old cronjobs or lifecycle jobs execution in error, your global job status will be in ",Object(o.b)("inlineCode",{parentName:"p"},"Warning"),".\nYou have the possibility to clear these old executions by clicking on the ",Object(o.b)("inlineCode",{parentName:"p"},"Clear status")," button in the status banner of your job."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deployment/clear_job_status.png",alt:"Clear status"})),Object(o.b)("h2",{id:"deployment-statuses"},"Deployment Statuses"),Object(o.b)("p",null,"When you access an environment on your ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),", you can check:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.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(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"the deployment status of each service in that specific environment"),", thanks to the label displayed in the ",Object(o.b)("inlineCode",{parentName:"p"},"Service status")," column. This corresponds to the status of the last deployment performed on the service."),Object(o.b)("p",{parentName:"li"},"Here are all the possible deployment statuses for both environments and services:")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"QUEUED")," (temporary state).")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"BUILDING")," (temporary state).")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"BUILDING ERROR")," (final state).")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"DEPLOYING")," (temporary state).")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"DEPLOYMENT ERROR")," (final state).")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"CANCELLING BUILDING")," (temporary state).")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"CANCELLED")," (temporary state).")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"DEPLOYMENT OK")," (final state)."))),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.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},447: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({}),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,o=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=b(n),m=a,d=p["".concat(c,".").concat(m)]||p[m]||u[m]||o;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 o=n.length,c=new Array(o);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: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),c=n(39),i=n(458),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?o.a.createElement(c.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})):o.a.createElement("a",Object(a.a)({},e,{href:b}))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(454),c=n(447),i=n.n(c);n(134);t.a=function(e){var t=e.children,n=e.className,a=e.badge,c=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"},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-"+(l||"chevron-right")+" arrow"}))));return b?r.a.createElement("a",{href:p,target:b,className:u},m):r.a.createElement(o.a,{to:p,className:u},m)}},458: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.dd6d1fd5.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[269],{421: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),o=(n(0),n(451)),c=(n(459),n(450)),i=(n(455),{last_modified_on:"2024-07-03",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:"Clear old job executions",id:"clear-old-job-executions",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(o.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"From any environment window on your ",Object(o.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(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deployment/run_deployment_statuses.png",alt:"Statuses"})),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}),"1"),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"The dot in the service tab shows the environment running status. ",Object(o.b)("br",null)," For more information, see the Environment Statuses section below.")),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}),"The dot in the deployment tab shows the environment deployment status. ",Object(o.b)("br",null)," For more information, see the Deployment Statuses section below.")),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}),'The label in the column "Service status" represents the running status of the service. ',Object(o.b)("br",null)," For more information, see Service Statuses section below.")),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}),'The label in the column "Last deployment" represents the status of the latest deployment of the service. ',Object(o.b)("br",null)," For more information, see Deployment Statuses section below.")))),Object(o.b)("h2",{id:"running-statuses"},"Running Statuses"),Object(o.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(o.b)("h2",{id:"environment-statuses"},"Environment Statuses"),Object(o.b)("p",null,"When you access an environment on your ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),", you can check its status in real-time."),Object(o.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(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}),"Status"),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}),"STOPPED ",Object(o.b)("em",{parentName:"td"},"(Gray dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All the services are stopped.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STARTING ",Object(o.b)("em",{parentName:"td"},"(Loading Icon)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 service is starting.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STOPPING ",Object(o.b)("em",{parentName:"td"},"(Loading Icon)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 service is stopping.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"RUNNING ",Object(o.b)("em",{parentName:"td"},"(Green dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All services are running correctly.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ERROR ",Object(o.b)("em",{parentName:"td"},"(Red dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All services are in error status.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"WARNING ",Object(o.b)("em",{parentName:"td"},"(Orange dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 service is in error status (but not all of them).")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"COMPLETED ",Object(o.b)("em",{parentName:"td"},"(Green dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"The job execution has completed (only for cronjob and lifecycle jobs).")))),Object(o.b)("h2",{id:"service-statuses"},"Service Statuses"),Object(o.b)("p",null,"When you access an environment on your ",Object(o.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(o.b)("p",null,"Here are all the possible service statuses:"),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}),"Status"),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}),"STOPPED ",Object(o.b)("em",{parentName:"td"},"(Gray dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All the application instances are stopped.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STARTING ",Object(o.b)("em",{parentName:"td"},"(Loading Icon)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 application instance is starting.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"STOPPING ",Object(o.b)("em",{parentName:"td"},"(Loading Icon)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"At least 1 application instance is stopping.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"RUNNING ",Object(o.b)("em",{parentName:"td"},"(Green dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All application instances are running correctly.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"ERROR ",Object(o.b)("em",{parentName:"td"},"(Red dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"All application instances are in error status.")),Object(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"WARNING ",Object(o.b)("em",{parentName:"td"},"(Orange dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.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(o.b)("tr",{parentName:"tbody"},Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),"Completed ",Object(o.b)("em",{parentName:"td"},"(Green dot)")),Object(o.b)("td",Object(a.a)({parentName:"tr"},{align:null}),Object(o.b)("em",{parentName:"td"},"(Valid for Lifecycle and Cronjob only)")," The job was correctly executed.")))),Object(o.b)("p",null,"The service status is computed based on the status of each ",Object(o.b)("inlineCode",{parentName:"p"},"Kubernetes pod")," deployed for this application."),Object(o.b)("h3",{id:"pod-status-application-instances"},"Pod status (Application instances)"),Object(o.b)("p",null,"You can check on the ",Object(o.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(o.b)("p",null,"Within this page you will have a view of:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},"the number of running instances of your application"),Object(o.b)("li",{parentName:"ul"},"the status of each instance"),Object(o.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(o.b)("p",null,"By clicking on ",Object(o.b)("inlineCode",{parentName:"p"},"Logs"),", you will be redirected to the service logs specifically filtered for this pod."),Object(o.b)("h3",{id:"clear-old-job-executions"},"Clear old job executions"),Object(o.b)("p",null,"If you have old cronjobs or lifecycle jobs execution in error, your global job status will be in ",Object(o.b)("inlineCode",{parentName:"p"},"Warning"),".\nYou have the possibility to clear these old executions by clicking on the ",Object(o.b)("inlineCode",{parentName:"p"},"Clear status")," button in the status banner of your job."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"/img/deployment/clear_job_status.png",alt:"Clear status"})),Object(o.b)("h2",{id:"deployment-statuses"},"Deployment Statuses"),Object(o.b)("p",null,"When you access an environment on your ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://console.qovery.com"}),"Qovery Console"),", you can check:"),Object(o.b)("ul",null,Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.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(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"the deployment status of each service in that specific environment"),", thanks to the label displayed in the ",Object(o.b)("inlineCode",{parentName:"p"},"Service status")," column. This corresponds to the status of the last deployment performed on the service."),Object(o.b)("p",{parentName:"li"},"Here are all the possible deployment statuses for both environments and services:")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"QUEUED")," (temporary state).")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"BUILDING")," (temporary state).")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"BUILDING ERROR")," (final state).")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"DEPLOYING")," (temporary state).")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"DEPLOYMENT ERROR")," (final state).")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"CANCELLING BUILDING")," (temporary state).")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"CANCELLED")," (temporary state).")),Object(o.b)("li",{parentName:"ul"},Object(o.b)("p",{parentName:"li"},Object(o.b)("strong",{parentName:"p"},"DEPLOYMENT OK")," (final state)."))),Object(o.b)(c.a,{type:"info",mdxType:"Alert"},Object(o.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},449: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({}),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,o=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=b(n),m=a,d=p["".concat(c,".").concat(m)]||p[m]||u[m]||o;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 o=n.length,c=new Array(o);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: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),c=n(39),i=n(460),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?o.a.createElement(c.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})):o.a.createElement("a",Object(a.a)({},e,{href:b}))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(456),c=n(449),i=n.n(c);n(134);t.a=function(e){var t=e.children,n=e.className,a=e.badge,c=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"},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-"+(l||"chevron-right")+" arrow"}))));return b?r.a.createElement("a",{href:p,target:b,className:u},m):r.a.createElement(o.a,{to:p,className:u},m)}},460: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.65625a64.js.LICENSE.txt b/e3c664e0.dd6d1fd5.js.LICENSE.txt similarity index 100% rename from e4768112.65625a64.js.LICENSE.txt rename to e3c664e0.dd6d1fd5.js.LICENSE.txt diff --git a/e4310ee0.3e9005cc.js b/e4310ee0.3bf97498.js similarity index 90% rename from e4310ee0.3e9005cc.js rename to e4310ee0.3bf97498.js index 890ef5f771..5545556e73 100644 --- a/e4310ee0.3e9005cc.js +++ b/e4310ee0.3bf97498.js @@ -1,2 +1,2 @@ -/*! For license information please see e4310ee0.3e9005cc.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[268],{420: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(449)),i=n(456),c=n(453),u=(n(448),{last_modified_on:"2024-02-27",$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://discuss.qovery.com/"}),"find us on our forum")," or on Intercom depending on your support plan."))}p.isMDXComponent=!0},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(447),n(455)),i=n.n(a);n(133);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"),"."))}},459: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.3bf97498.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[270],{422: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(451)),i=n(458),c=n(455),u=(n(450),{last_modified_on:"2024-02-27",$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://discuss.qovery.com/"}),"find us on our forum")," or on Intercom depending on your support plan."))}p.isMDXComponent=!0},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(449),n(457)),i=n.n(a);n(133);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"),"."))}},461: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.3e305717.js.LICENSE.txt b/e4310ee0.3bf97498.js.LICENSE.txt similarity index 100% rename from e5653b8d.3e305717.js.LICENSE.txt rename to e4310ee0.3bf97498.js.LICENSE.txt diff --git a/bdd6d8c6.031987e5.js b/e4768112.4fb1b12f.js similarity index 92% rename from bdd6d8c6.031987e5.js rename to e4768112.4fb1b12f.js index a46ca8d4a3..f8866c57ce 100644 --- a/bdd6d8c6.031987e5.js +++ b/e4768112.4fb1b12f.js @@ -1,2 +1,2 @@ -/*! For license information please see bdd6d8c6.031987e5.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[219],{370: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(449)),c=n(456),i=(n(448),n(453)),s=(n(457),{last_modified_on:"2023-12-30",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),c=n(39),i=n(458),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}))}},455:function(e,t,n){"use strict";var a=n(459),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("&"):""}},456:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(447),n(455)),c=n.n(o);n(133);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"),"."))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(454),c=n(447),i=n.n(c);n(134);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)}},458:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},459: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.4fb1b12f.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[271],{423: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(451)),c=n(458),i=(n(450),n(455)),s=(n(459),{last_modified_on:"2023-12-30",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),c=n(39),i=n(460),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}))}},457:function(e,t,n){"use strict";var a=n(461),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("&"):""}},458:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(449),n(457)),c=n.n(o);n(133);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"),"."))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(456),c=n(449),i=n.n(c);n(134);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)}},460:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},461: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.90e6c49b.js.LICENSE.txt b/e4768112.4fb1b12f.js.LICENSE.txt similarity index 100% rename from e5b9b0aa.90e6c49b.js.LICENSE.txt rename to e4768112.4fb1b12f.js.LICENSE.txt diff --git a/ba43933d.134f4e52.js b/e5653b8d.fa9b4941.js similarity index 91% rename from ba43933d.134f4e52.js rename to e5653b8d.fa9b4941.js index 19f2ef5de7..839567de53 100644 --- a/ba43933d.134f4e52.js +++ b/e5653b8d.fa9b4941.js @@ -1,2 +1,2 @@ -/*! For license information please see ba43933d.134f4e52.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[212],{363: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(449)),i=n(448),l=(n(453),n(457),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(458),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}))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(454),i=n(447),l=n.n(i);n(134);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)}},458: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.fa9b4941.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[272],{424: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(451)),i=n(450),l=(n(455),n(459),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(460),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}))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(456),i=n(449),l=n.n(i);n(134);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)}},460: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/e7d0ec68.6bd7c4df.js.LICENSE.txt b/e5653b8d.fa9b4941.js.LICENSE.txt similarity index 100% rename from e7d0ec68.6bd7c4df.js.LICENSE.txt rename to e5653b8d.fa9b4941.js.LICENSE.txt diff --git a/e5b9b0aa.90e6c49b.js b/e5b9b0aa.23140eee.js similarity index 90% rename from e5b9b0aa.90e6c49b.js rename to e5b9b0aa.23140eee.js index 5abeb91ce3..12fb818ed9 100644 --- a/e5b9b0aa.90e6c49b.js +++ b/e5b9b0aa.23140eee.js @@ -1,2 +1,2 @@ -/*! For license information please see e5b9b0aa.90e6c49b.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[271],{423: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(449)),i=(r(456),r(453),r(448)),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:"Monitor and reduce Kubernetes spend with Kubecost",permalink:"/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost"}},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},447: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}},452: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""}}})},453:function(e,t,r){"use strict";r(452);var n=r(0),a=r.n(n),o=r(448);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)}},455:function(e,t,r){"use strict";var n=r(459),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("&"):""}},456:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(447),r(455)),i=r.n(o);r(133);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"),"."))}},459: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.23140eee.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[273],{425: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(451)),i=(r(458),r(455),r(450)),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:"Monitor and reduce Kubernetes spend with Kubecost",permalink:"/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost"}},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},449: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}},454: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""}}})},455:function(e,t,r){"use strict";r(454);var n=r(0),a=r.n(n),o=r(450);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)}},457:function(e,t,r){"use strict";var n=r(461),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("&"):""}},458:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=(r(449),r(457)),i=r.n(o);r(133);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"),"."))}},461: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/e862b20f.67e837bc.js.LICENSE.txt b/e5b9b0aa.23140eee.js.LICENSE.txt similarity index 100% rename from e862b20f.67e837bc.js.LICENSE.txt rename to e5b9b0aa.23140eee.js.LICENSE.txt diff --git a/e7d0ec68.6bd7c4df.js b/e7d0ec68.6dacfa29.js similarity index 87% rename from e7d0ec68.6bd7c4df.js rename to e7d0ec68.6dacfa29.js index d4ae89f505..366f574d60 100644 --- a/e7d0ec68.6bd7c4df.js +++ b/e7d0ec68.6dacfa29.js @@ -1,2 +1,2 @@ -/*! For license information please see e7d0ec68.6bd7c4df.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[272],{424: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(449)),i=(n(456),n(453),n(448)),c={last_modified_on:"2024-01-09",$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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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.6dacfa29.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[274],{426: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(451)),i=(n(458),n(455),n(450)),c={last_modified_on:"2024-01-09",$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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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/e8b0321f.04eedc3a.js.LICENSE.txt b/e7d0ec68.6dacfa29.js.LICENSE.txt similarity index 100% rename from e8b0321f.04eedc3a.js.LICENSE.txt rename to e7d0ec68.6dacfa29.js.LICENSE.txt diff --git a/e862b20f.67e837bc.js b/e862b20f.b28933bf.js similarity index 89% rename from e862b20f.67e837bc.js rename to e862b20f.b28933bf.js index 360085b1d8..7404de3708 100644 --- a/e862b20f.67e837bc.js +++ b/e862b20f.b28933bf.js @@ -1,2 +1,2 @@ -/*! For license information please see e862b20f.67e837bc.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[273],{425:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return s})),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(449)),c=r(457),i={last_modified_on:"2023-12-30",title:"Managed By Qovery",sidebar_label:"hidden",hide_pagination:!0},s={id:"getting-started/install-qovery/aws/cluster-managed-by-qovery",title:"Managed By Qovery",description:"import Jump from '@site/src/components/Jump';",source:"@site/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery.md",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery",sidebar_label:"hidden",sidebar:"docs",previous:{title:"AWS",permalink:"/docs/getting-started/install-qovery/aws"},next:{title:"Quickstart",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart"}},u=[],l={rightToc:u};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,"Don't be shy, pick the first page you want to read and start your journey with Qovery."),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart",mdxType:"Jump"},"Quickstart"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials",mdxType:"Jump"},"Create Credentials"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure",mdxType:"Jump"},"Infrastructure"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/faq",mdxType:"Jump"},"FAQ"))}p.isMDXComponent=!0},447: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({}),l=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=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(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),f=n,m=p["".concat(c,".").concat(f)]||p[f]||d[f]||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]=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:n,c[1]=i;for(var u=2;u0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):o.a.createElement("a",Object(n.a)({},e,{href:l}))}},457:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(454),c=r(447),i=r.n(c);r(134);t.a=function(e){var t=e.children,r=e.className,n=e.badge,c=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,d=i()("jump-to","jump-to--"+u,r),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"},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 l?a.a.createElement("a",{href:p,target:l,className:d},f):a.a.createElement(o.a,{to:p,className:d},f)}},458: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 e862b20f.b28933bf.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[275],{427:function(e,t,r){"use strict";r.r(t),r.d(t,"frontMatter",(function(){return i})),r.d(t,"metadata",(function(){return s})),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(451)),c=r(459),i={last_modified_on:"2023-12-30",title:"Managed By Qovery",sidebar_label:"hidden",hide_pagination:!0},s={id:"getting-started/install-qovery/aws/cluster-managed-by-qovery",title:"Managed By Qovery",description:"import Jump from '@site/src/components/Jump';",source:"@site/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery.md",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery",sidebar_label:"hidden",sidebar:"docs",previous:{title:"AWS",permalink:"/docs/getting-started/install-qovery/aws"},next:{title:"Quickstart",permalink:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart"}},u=[],l={rightToc:u};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,"Don't be shy, pick the first page you want to read and start your journey with Qovery."),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart",mdxType:"Jump"},"Quickstart"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials",mdxType:"Jump"},"Create Credentials"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure",mdxType:"Jump"},"Infrastructure"),Object(o.b)(c.a,{to:"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/faq",mdxType:"Jump"},"FAQ"))}p.isMDXComponent=!0},449: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({}),l=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=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(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),f=n,m=p["".concat(c,".").concat(f)]||p[f]||d[f]||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]=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:n,c[1]=i;for(var u=2;u0)&&(t.unobserve(r),t.disconnect(),n())}))}))).observe(r))},to:l})):o.a.createElement("a",Object(n.a)({},e,{href:l}))}},459:function(e,t,r){"use strict";var n=r(0),a=r.n(n),o=r(456),c=r(449),i=r.n(c);r(134);t.a=function(e){var t=e.children,r=e.className,n=e.badge,c=e.leftIcon,s=e.rightIcon,u=e.size,l=e.target,p=e.to,d=i()("jump-to","jump-to--"+u,r),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"},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 l?a.a.createElement("a",{href:p,target:l,className:d},f):a.a.createElement(o.a,{to:p,className:d},f)}},460: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/e9c994cf.86985754.js.LICENSE.txt b/e862b20f.b28933bf.js.LICENSE.txt similarity index 100% rename from e9c994cf.86985754.js.LICENSE.txt rename to e862b20f.b28933bf.js.LICENSE.txt diff --git a/e8b0321f.04eedc3a.js b/e8b0321f.79f069c7.js similarity index 91% rename from e8b0321f.04eedc3a.js rename to e8b0321f.79f069c7.js index 29bae43c19..24a5ae87f5 100644 --- a/e8b0321f.04eedc3a.js +++ b/e8b0321f.79f069c7.js @@ -1,2 +1,2 @@ -/*! For license information please see e8b0321f.04eedc3a.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[274],{426: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(449)),i=(a(456),a(453),a(448),{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},447: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}},452: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""}}})},453:function(e,t,a){"use strict";a(452);var r=a(0),n=a.n(r),o=a(448);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)}},455:function(e,t,a){"use strict";var r=a(459),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("&"):""}},456:function(e,t,a){"use strict";var r=a(0),n=a.n(r),o=(a(447),a(455)),i=a.n(o);a(133);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"),"."))}},459: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.79f069c7.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[276],{428: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(451)),i=(a(458),a(455),a(450),{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},449: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}},454: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""}}})},455:function(e,t,a){"use strict";a(454);var r=a(0),n=a.n(r),o=a(450);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)}},457:function(e,t,a){"use strict";var r=a(461),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("&"):""}},458:function(e,t,a){"use strict";var r=a(0),n=a.n(r),o=(a(449),a(457)),i=a.n(o);a(133);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"),"."))}},461: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.5d13d5ce.js.LICENSE.txt b/e8b0321f.79f069c7.js.LICENSE.txt similarity index 100% rename from eb0c7ce5.5d13d5ce.js.LICENSE.txt rename to e8b0321f.79f069c7.js.LICENSE.txt diff --git a/e9c994cf.86985754.js b/e9c994cf.e06732fe.js similarity index 93% rename from e9c994cf.86985754.js rename to e9c994cf.e06732fe.js index 559b44937a..de062042a2 100644 --- a/e9c994cf.86985754.js +++ b/e9c994cf.e06732fe.js @@ -1,2 +1,2 @@ -/*! For license information please see e9c994cf.86985754.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[275],{427: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(449)),i=n(456),c=n(448),l=n(453),u=(n(457),{last_modified_on:"2024-07-12",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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"},"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)("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 Network")),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},454:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(458),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}))}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},457:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(454),i=n(447),c=n.n(i);n(134);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)}},458:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},459: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.e06732fe.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[277],{429: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(451)),i=n(458),c=n(450),l=n(455),u=(n(459),{last_modified_on:"2024-07-12",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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"},"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)("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 Network")),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},456:function(e,t,n){"use strict";var r=n(1),a=n(0),o=n.n(a),i=n(39),c=n(460),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}))}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},459:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=n(456),i=n(449),c=n.n(i);n(134);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)}},460:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},461: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.f207f878.js.LICENSE.txt b/e9c994cf.e06732fe.js.LICENSE.txt similarity index 100% rename from f26e55ec.f207f878.js.LICENSE.txt rename to e9c994cf.e06732fe.js.LICENSE.txt diff --git a/eb0c7ce5.5d13d5ce.js b/eb0c7ce5.ce1e0e04.js similarity index 90% rename from eb0c7ce5.5d13d5ce.js rename to eb0c7ce5.ce1e0e04.js index 9a6da25e7c..0b59c78278 100644 --- a/eb0c7ce5.5d13d5ce.js +++ b/eb0c7ce5.ce1e0e04.js @@ -1,2 +1,2 @@ -/*! For license information please see eb0c7ce5.5d13d5ce.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[276],{428: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(449)),c=n(456),i=n(448),l=n(453),u=(n(457),{last_modified_on:"2023-12-30",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},454:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),c=n(39),i=n(458),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}))}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(447),n(455)),c=n.n(a);n(133);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"),"."))}},457:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(454),c=n(447),i=n.n(c);n(134);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)}},458:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},459: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.ce1e0e04.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[278],{430: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(451)),c=n(458),i=n(450),l=n(455),u=(n(459),{last_modified_on:"2023-12-30",$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","installation_guide: 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:"installation_guide: aws",permalink:"/guides/tags/installation-guide-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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},456:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),c=n(39),i=n(460),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}))}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(449),n(457)),c=n.n(a);n(133);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"),"."))}},459:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(456),c=n(449),i=n.n(c);n(134);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)}},460:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},461: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.c4dd8079.js.LICENSE.txt b/eb0c7ce5.ce1e0e04.js.LICENSE.txt similarity index 100% rename from f3d8c143.c4dd8079.js.LICENSE.txt rename to eb0c7ce5.ce1e0e04.js.LICENSE.txt diff --git a/f0f90e68.49ee1f65.js b/f0f90e68.bd315c06.js similarity index 94% rename from f0f90e68.49ee1f65.js rename to f0f90e68.bd315c06.js index f6eb9a0f1e..db1aaf62be 100644 --- a/f0f90e68.49ee1f65.js +++ b/f0f90e68.bd315c06.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[277],{429: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(449)),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},449: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.600ad4d0.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[281],{433: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(451)),i=o(450),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},449: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/f6a16982.1044c29f.js.LICENSE.txt b/f26e55ec.600ad4d0.js.LICENSE.txt similarity index 100% rename from f6a16982.1044c29f.js.LICENSE.txt rename to f26e55ec.600ad4d0.js.LICENSE.txt diff --git a/f3d8c143.c4dd8079.js b/f3d8c143.e9d66b81.js similarity index 93% rename from f3d8c143.c4dd8079.js rename to f3d8c143.e9d66b81.js index 3bf8b0f0e3..1c49637328 100644 --- a/f3d8c143.c4dd8079.js +++ b/f3d8c143.e9d66b81.js @@ -1,2 +1,2 @@ -/*! For license information please see f3d8c143.c4dd8079.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[280],{432: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(449)),i=o(448),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},447: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.e9d66b81.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[282],{434: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(451)),i=o(450),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},449: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.07a63b63.js.LICENSE.txt b/f3d8c143.e9d66b81.js.LICENSE.txt similarity index 100% rename from f756422c.07a63b63.js.LICENSE.txt rename to f3d8c143.e9d66b81.js.LICENSE.txt diff --git a/f6a16982.1044c29f.js b/f6a16982.2e869e6b.js similarity index 89% rename from f6a16982.1044c29f.js rename to f6a16982.2e869e6b.js index 34ddd12b32..2038a23b58 100644 --- a/f6a16982.1044c29f.js +++ b/f6a16982.2e869e6b.js @@ -1,2 +1,2 @@ -/*! For license information please see f6a16982.1044c29f.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[281],{433: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 n=r(1),a=r(9),o=(r(0),r(449)),i=r(448),l={last_modified_on:"2024-01-26",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Microsoft Azure account",description:"Learn how to install Qovery on your Microsoft Azure account",series_position:5,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: azure"]},c={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery on your Microsoft Azure account",description:"Learn how to install Qovery on your Microsoft Azure account",permalink:"/guides/installation-guide/guide-microsoft-azure",readingTime:"1 min read",seriesPosition:5,source:"@site/guides/installation-guide/guide-microsoft-azure.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: azure",permalink:"/guides/tags/installation-guide-azure"}],title:"Install Qovery on your Microsoft Azure account",truncated:!1,prevItem:{title:"Install Qovery on your Kubernetes cluster",permalink:"/guides/installation-guide/guide-kubernetes"},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=[],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)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Access our new installation guide of Qovery on Azure ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/azure/"}),"here"))))}p.isMDXComponent=!0},447: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):l({},t,{},e)),r},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)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,g=p["".concat(i,".").concat(d)]||p[d]||f[d]||o;return r?a.a.createElement(g,l({ref:t},u,{components:r})):a.a.createElement(g,l({ref:t},u))}));function g(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 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,r),c=i>2?arguments[2]:void 0,u=void 0===c?r:a(c,r);u>l;)t[l++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see f6a16982.2e869e6b.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[283],{435: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 n=r(1),a=r(9),o=(r(0),r(451)),i=r(450),l={last_modified_on:"2024-01-26",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Microsoft Azure account",description:"Learn how to install Qovery on your Microsoft Azure account",series_position:5,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: azure"]},c={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery on your Microsoft Azure account",description:"Learn how to install Qovery on your Microsoft Azure account",permalink:"/guides/installation-guide/guide-microsoft-azure",readingTime:"1 min read",seriesPosition:5,source:"@site/guides/installation-guide/guide-microsoft-azure.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: azure",permalink:"/guides/tags/installation-guide-azure"}],title:"Install Qovery on your Microsoft Azure account",truncated:!1,prevItem:{title:"Install Qovery on your Kubernetes cluster",permalink:"/guides/installation-guide/guide-kubernetes"},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=[],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)(i.a,{type:"warning",mdxType:"Alert"},Object(o.b)("p",null,"Access our new installation guide of Qovery on Azure ",Object(o.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/azure/"}),"here"))))}p.isMDXComponent=!0},449: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):l({},t,{},e)),r},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)}},d=Object(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,g=p["".concat(i,".").concat(d)]||p[d]||f[d]||o;return r?a.a.createElement(g,l({ref:t},u,{components:r})):a.a.createElement(g,l({ref:t},u))}));function g(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 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,r),c=i>2?arguments[2]:void 0,u=void 0===c?r:a(c,r);u>l;)t[l++]=e;return t}}}]); \ No newline at end of file diff --git a/fb1d0a83.25a9ea35.js.LICENSE.txt b/f6a16982.2e869e6b.js.LICENSE.txt similarity index 100% rename from fb1d0a83.25a9ea35.js.LICENSE.txt rename to f6a16982.2e869e6b.js.LICENSE.txt diff --git a/ab8f5b83.8fc4688e.js b/f7098925.d4805627.js similarity index 96% rename from ab8f5b83.8fc4688e.js rename to f7098925.d4805627.js index 0ece8198e1..ae5f12797d 100644 --- a/ab8f5b83.8fc4688e.js +++ b/f7098925.d4805627.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[187],{339: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(449)),i=n(448),l=n(457),s=n(456),c=n(461),b=n(464),u=n(453),p={last_modified_on:"2024-05-03",$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://console.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.png",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 a headless (without GUI) environment, you can use the following command to sign up and sign in:"),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 Qovery sign-up page will open. Follow the instructions to sign up and sign 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},448:function(e,t,n){"use strict";n(450);var a=n(0),r=n.n(a),o=n(447),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)}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(448);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)}},454:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(458),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}))}},456:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},457:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(454),i=n(447),l=n.n(i);n(134);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)}},458:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},461:function(e,t,n){"use strict";var a=n(1),r=(n(465),n(462),n(52),n(29),n(22),n(21),n(0)),o=n.n(r),i=n(469),l=n(447),s=n.n(l),c=n(455),b=n.n(c),u=n(468),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])}},464: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([[284],{436: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(451)),i=n(450),l=n(459),s=n(458),c=n(463),b=n(466),u=n(455),p={last_modified_on:"2024-05-03",$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://console.qovery.com/"},Object(o.b)("img",{src:"/img/Qovery_Sign_Up_Page.png",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 a headless (without GUI) environment, you can use the following command to sign up and sign in:"),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 Qovery sign-up page will open. Follow the instructions to sign up and sign 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},450:function(e,t,n){"use strict";n(452);var a=n(0),r=n.n(a),o=n(449),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)}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var a=n(0),r=n.n(a),o=n(450);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)}},456:function(e,t,n){"use strict";var a=n(1),r=n(0),o=n.n(r),i=n(39),l=n(460),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}))}},458:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},459:function(e,t,n){"use strict";var a=n(0),r=n.n(a),o=n(456),i=n(449),l=n.n(i);n(134);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)}},460:function(e,t,n){"use strict";function a(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return a}))},463:function(e,t,n){"use strict";var a=n(1),r=(n(467),n(464),n(52),n(29),n(22),n(21),n(0)),o=n.n(r),i=n(471),l=n(449),s=n.n(l),c=n(457),b=n.n(c),u=n(470),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])}},466: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.07a63b63.js b/f756422c.5085fdae.js similarity index 94% rename from f756422c.07a63b63.js rename to f756422c.5085fdae.js index a766e569c5..1be59dca06 100644 --- a/f756422c.07a63b63.js +++ b/f756422c.5085fdae.js @@ -1,2 +1,2 @@ -/*! For license information please see f756422c.07a63b63.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[283],{435: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(449)),a=n(448),c=n(456),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},447: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}},455:function(e,t,n){"use strict";var o=n(459),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("&"):""}},456:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(447),n(455)),a=n.n(i);n(133);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"),"."))}},459: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.5085fdae.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[285],{437: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(451)),a=n(450),c=n(458),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},449: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}},457:function(e,t,n){"use strict";var o=n(461),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("&"):""}},458:function(e,t,n){"use strict";var o=n(0),r=n.n(o),i=(n(449),n(457)),a=n.n(i);n(133);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"),"."))}},461: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.0a84d392.js.LICENSE.txt b/f756422c.5085fdae.js.LICENSE.txt similarity index 100% rename from fc376fea.0a84d392.js.LICENSE.txt rename to f756422c.5085fdae.js.LICENSE.txt diff --git a/f7aa8e39.33a54bf7.js b/f7aa8e39.711a98b6.js similarity index 72% rename from f7aa8e39.33a54bf7.js rename to f7aa8e39.711a98b6.js index 58f6873524..241735bd19 100644 --- a/f7aa8e39.33a54bf7.js +++ b/f7aa8e39.711a98b6.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[284],{436: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([[286],{438: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.25a9ea35.js b/fb1d0a83.e988067a.js similarity index 90% rename from fb1d0a83.25a9ea35.js rename to fb1d0a83.e988067a.js index 5f9def4bcb..dfa373eca7 100644 --- a/fb1d0a83.25a9ea35.js +++ b/fb1d0a83.e988067a.js @@ -1,2 +1,2 @@ -/*! For license information please see fb1d0a83.25a9ea35.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[285],{437: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(449)),i=n(456),c=n(448),s=n(453),u=(n(457),{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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),o=n.n(r),a=n(448);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)}},454:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),c=n(458),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}))}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(447),n(455)),i=n.n(a);n(133);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"),"."))}},457:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(454),i=n(447),c=n.n(i);n(134);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)}},458:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},459: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.e988067a.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[287],{439: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(451)),i=n(458),c=n(450),s=n(455),u=(n(459),{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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),o=n.n(r),a=n(450);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)}},456:function(e,t,n){"use strict";var r=n(1),o=n(0),a=n.n(o),i=n(39),c=n(460),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}))}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=(n(449),n(457)),i=n.n(a);n(133);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"),"."))}},459:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(456),i=n(449),c=n.n(i);n(134);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)}},460:function(e,t,n){"use strict";function r(e){return!1===/^(https?:|\/\/)/.test(e)}n.d(t,"a",(function(){return r}))},461: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.d0661f10.js.LICENSE.txt b/fb1d0a83.e988067a.js.LICENSE.txt similarity index 100% rename from fcb698a1.d0661f10.js.LICENSE.txt rename to fb1d0a83.e988067a.js.LICENSE.txt diff --git a/fc376fea.0a84d392.js b/fc376fea.7b584c7f.js similarity index 91% rename from fc376fea.0a84d392.js rename to fc376fea.7b584c7f.js index a714d16991..4363c18bf6 100644 --- a/fc376fea.0a84d392.js +++ b/fc376fea.7b584c7f.js @@ -1,2 +1,2 @@ -/*! For license information please see fc376fea.0a84d392.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[286],{438: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(449)),i=n(457),c={last_modified_on:"2024-01-22",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},447: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}))}},457:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(454),i=n(447),c=n.n(i);n(134);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)}},458: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 fc376fea.7b584c7f.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[288],{440: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(451)),i=n(459),c={last_modified_on:"2024-01-22",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},449: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}))}},459:function(e,t,n){"use strict";var r=n(0),o=n.n(r),a=n(456),i=n(449),c=n.n(i);n(134);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)}},460: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/ff0cde69.0a351ac4.js.LICENSE.txt b/fc376fea.7b584c7f.js.LICENSE.txt similarity index 100% rename from ff0cde69.0a351ac4.js.LICENSE.txt rename to fc376fea.7b584c7f.js.LICENSE.txt diff --git a/fcb698a1.d0661f10.js b/fcb698a1.bcd27964.js similarity index 89% rename from fcb698a1.d0661f10.js rename to fcb698a1.bcd27964.js index d24d165e77..40413a6a8b 100644 --- a/fcb698a1.d0661f10.js +++ b/fcb698a1.bcd27964.js @@ -1,2 +1,2 @@ -/*! For license information please see fcb698a1.d0661f10.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[287],{439: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(449)),o=n(457),i={last_modified_on:"2024-01-03",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},447: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}))}},457:function(e,t,n){"use strict";var r=n(0),a=n.n(r),c=n(454),o=n(447),i=n.n(o);n(134);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)}},458: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.bcd27964.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[289],{441: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(451)),o=n(459),i={last_modified_on:"2024-01-03",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},449: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}))}},459:function(e,t,n){"use strict";var r=n(0),a=n.n(r),c=n(456),o=n(449),i=n.n(o);n(134);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)}},460: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/ff2506fd.b1ec280b.js.LICENSE.txt b/fcb698a1.bcd27964.js.LICENSE.txt similarity index 100% rename from ff2506fd.b1ec280b.js.LICENSE.txt rename to fcb698a1.bcd27964.js.LICENSE.txt diff --git a/ff0cde69.0a351ac4.js b/ff0cde69.7c13acdb.js similarity index 93% rename from ff0cde69.0a351ac4.js rename to ff0cde69.7c13acdb.js index 7ae9c44124..9abeb740c9 100644 --- a/ff0cde69.0a351ac4.js +++ b/ff0cde69.7c13acdb.js @@ -1,2 +1,2 @@ -/*! For license information please see ff0cde69.0a351ac4.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[288],{440: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(449)),i=n(453),c=n(456),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},447: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}},452: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""}}})},453:function(e,t,n){"use strict";n(452);var r=n(0),a=n.n(r),o=n(448);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)}},455:function(e,t,n){"use strict";var r=n(459),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("&"):""}},456:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(447),n(455)),i=n.n(o);n(133);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"),"."))}},459: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.7c13acdb.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[290],{442: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(451)),i=n(455),c=n(458),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},449: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}},454: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""}}})},455:function(e,t,n){"use strict";n(454);var r=n(0),a=n.n(r),o=n(450);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)}},457:function(e,t,n){"use strict";var r=n(461),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("&"):""}},458:function(e,t,n){"use strict";var r=n(0),a=n.n(r),o=(n(449),n(457)),i=n.n(o);n(133);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"),"."))}},461: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/ff91a867.18b335ef.js.LICENSE.txt b/ff0cde69.7c13acdb.js.LICENSE.txt similarity index 100% rename from ff91a867.18b335ef.js.LICENSE.txt rename to ff0cde69.7c13acdb.js.LICENSE.txt diff --git a/dffbf523.17aebafc.js b/ff2506fd.899342f7.js similarity index 89% rename from dffbf523.17aebafc.js rename to ff2506fd.899342f7.js index be6ebefdb2..5d15315d71 100644 --- a/dffbf523.17aebafc.js +++ b/ff2506fd.899342f7.js @@ -1,2 +1,2 @@ -/*! For license information please see dffbf523.17aebafc.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[262],{414: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 c})),r.d(t,"default",(function(){return p}));var n=r(1),a=r(9),i=(r(0),r(449)),o=r(448),l={last_modified_on:"2024-01-02",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Kubernetes cluster",description:"Learn how to install Qovery on your own Kubernetes cluster (BYOK)",series_position:4,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: kubernetes"]},u={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery on your Kubernetes cluster",description:"Learn how to install Qovery on your own Kubernetes cluster (BYOK)",permalink:"/guides/installation-guide/guide-kubernetes",readingTime:"1 min read",seriesPosition:4,source:"@site/guides/installation-guide/guide-kubernetes.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: kubernetes",permalink:"/guides/tags/installation-guide-kubernetes"}],title:"Install Qovery on your Kubernetes cluster",truncated:!1,prevItem:{title:"Install Qovery on your Scaleway account",permalink:"/guides/installation-guide/guide-scaleway"},nextItem:{title:"Install Qovery on your Microsoft Azure account",permalink:"/guides/installation-guide/guide-microsoft-azure"}},c=[],s={rightToc:c};function p(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(i.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(i.b)(o.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"Access our new installation guide of Qovery on Kubernetes ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/"}),"here"))))}p.isMDXComponent=!0},447: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 i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=a.a.createContext({}),s=function(e){var t=a.a.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l({},t,{},e)),r},p=function(e){var t=s(e.components);return a.a.createElement(c.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(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,o=e.parentName,c=u(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,y=p["".concat(o,".").concat(d)]||p[d]||f[d]||i;return r?a.a.createElement(y,l({ref:t},c,{components:r})):a.a.createElement(y,l({ref:t},c))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,o=new Array(i);o[0]=d;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l.mdxType="string"==typeof e?e:n,o[1]=l;for(var c=2;c1?arguments[1]:void 0,r),u=o>2?arguments[2]:void 0,c=void 0===u?r:a(u,r);c>l;)t[l++]=e;return t}}}]); \ No newline at end of file +/*! For license information please see ff2506fd.899342f7.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[291],{443: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 c})),r.d(t,"default",(function(){return p}));var n=r(1),a=r(9),i=(r(0),r(451)),o=r(450),l={last_modified_on:"2024-01-02",$schema:"/.meta/.schemas/guides.json",title:"Install Qovery on your Kubernetes cluster",description:"Learn how to install Qovery on your own Kubernetes cluster (BYOK)",series_position:4,author_github:"https://github.com/evoxmusic",tags:["type: guide","installation_guide: kubernetes"]},u={categories:[{name:"installation-guide",title:"Installation Guide",description:null,permalink:"/guides/installation-guide"}],coverLabel:"Install Qovery on your Kubernetes cluster",description:"Learn how to install Qovery on your own Kubernetes cluster (BYOK)",permalink:"/guides/installation-guide/guide-kubernetes",readingTime:"1 min read",seriesPosition:4,source:"@site/guides/installation-guide/guide-kubernetes.md",tags:[{label:"type: guide",permalink:"/guides/tags/type-guide"},{label:"installation_guide: kubernetes",permalink:"/guides/tags/installation-guide-kubernetes"}],title:"Install Qovery on your Kubernetes cluster",truncated:!1,prevItem:{title:"Install Qovery on your Scaleway account",permalink:"/guides/installation-guide/guide-scaleway"},nextItem:{title:"Install Qovery on your Microsoft Azure account",permalink:"/guides/installation-guide/guide-microsoft-azure"}},c=[],s={rightToc:c};function p(e){var t=e.components,r=Object(a.a)(e,["components"]);return Object(i.b)("wrapper",Object(n.a)({},s,r,{components:t,mdxType:"MDXLayout"}),Object(i.b)(o.a,{type:"warning",mdxType:"Alert"},Object(i.b)("p",null,"Access our new installation guide of Qovery on Kubernetes ",Object(i.b)("a",Object(n.a)({parentName:"p"},{href:"/docs/getting-started/install-qovery/kubernetes/"}),"here"))))}p.isMDXComponent=!0},449: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 i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=a.a.createContext({}),s=function(e){var t=a.a.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l({},t,{},e)),r},p=function(e){var t=s(e.components);return a.a.createElement(c.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(n.forwardRef)((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,o=e.parentName,c=u(e,["components","mdxType","originalType","parentName"]),p=s(r),d=n,y=p["".concat(o,".").concat(d)]||p[d]||f[d]||i;return r?a.a.createElement(y,l({ref:t},c,{components:r})):a.a.createElement(y,l({ref:t},c))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,o=new Array(i);o[0]=d;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l.mdxType="string"==typeof e?e:n,o[1]=l;for(var c=2;c1?arguments[1]:void 0,r),u=o>2?arguments[2]:void 0,c=void 0===u?r:a(u,r);c>l;)t[l++]=e;return t}}}]); \ No newline at end of file diff --git a/ff2506fd.899342f7.js.LICENSE.txt b/ff2506fd.899342f7.js.LICENSE.txt new file mode 100644 index 0000000000..bae6dd8e22 --- /dev/null +++ b/ff2506fd.899342f7.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.18b335ef.js b/ff91a867.099f49ca.js similarity index 91% rename from ff91a867.18b335ef.js rename to ff91a867.099f49ca.js index 10f3783569..24bcd79f35 100644 --- a/ff91a867.18b335ef.js +++ b/ff91a867.099f49ca.js @@ -1,2 +1,2 @@ -/*! For license information please see ff91a867.18b335ef.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[290],{442: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(449)),o=t(448),c=t(457),s=t(453),l={last_modified_on:"2024-04-26",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/labels-annotations/",mdxType:"Jump"},"Labels annotations"),Object(i.b)(c.a,{to:"/docs/using-qovery/configuration/organization/members-rbac/",mdxType:"Jump"},"Members rbac"))}p.isMDXComponent=!0},447: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}},452: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""}}})},453:function(e,n,t){"use strict";t(452);var a=t(0),r=t.n(a),i=t(448);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)}},454:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),c=t(458),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}))}},457:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(454),o=t(447),c=t.n(o);t(134);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)}},458: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.099f49ca.js.LICENSE.txt */ +(window.webpackJsonp=window.webpackJsonp||[]).push([[292],{444: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(451)),o=t(450),c=t(459),s=t(455),l={last_modified_on:"2024-04-26",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/labels-annotations/",mdxType:"Jump"},"Labels annotations"),Object(i.b)(c.a,{to:"/docs/using-qovery/configuration/organization/members-rbac/",mdxType:"Jump"},"Members rbac"))}p.isMDXComponent=!0},449: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}},454: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""}}})},455:function(e,n,t){"use strict";t(454);var a=t(0),r=t.n(a),i=t(450);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)}},456:function(e,n,t){"use strict";var a=t(1),r=t(0),i=t.n(r),o=t(39),c=t(460),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}))}},459:function(e,n,t){"use strict";var a=t(0),r=t.n(a),i=t(456),o=t(449),c=t.n(o);t(134);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)}},460: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.099f49ca.js.LICENSE.txt b/ff91a867.099f49ca.js.LICENSE.txt new file mode 100644 index 0000000000..bae6dd8e22 --- /dev/null +++ b/ff91a867.099f49ca.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 0c6011478d..42ce18c1ef 100644 --- a/guides/advanced/continuous-integration/index.html +++ b/guides/advanced/continuous-integration/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 76904a2801..24bc3d2c19 100644 --- a/guides/advanced/costs-control/index.html +++ b/guides/advanced/costs-control/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 fd70bc87c1..c30c5529df 100644 --- a/guides/advanced/deploy-api-gateway/index.html +++ b/guides/advanced/deploy-api-gateway/index.html @@ -24,45 +24,45 @@ - + - + - + - + - + - + - + - +

                                                      Deploy API Gateway

                                                      Learn how to deploy an API Gateway with Qovery

                                                      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.

                                                      +
                                                      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 d8111bff0f..b6a3b22340 100644 --- a/guides/advanced/deploy-aws-services/index.html +++ b/guides/advanced/deploy-aws-services/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                      Stats
                                                      2 min read
                                                      Updated
                                                      - + - + - + - + - + - + - + - + diff --git a/guides/advanced/deploy-daemonset-with-karpenter/index.html b/guides/advanced/deploy-daemonset-with-karpenter/index.html new file mode 100644 index 0000000000..803c3a1e80 --- /dev/null +++ b/guides/advanced/deploy-daemonset-with-karpenter/index.html @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + +Deploy a DaemonSet in a Karpenter context | Qovery + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                      +

                                                      Deploy a DaemonSet in a Karpenter context

                                                      How to ensure your DaemonSet is well deployed when you are using Karpenter.

                                                      Karpenter is a great way to cut your AWS bill. It provides an easy and flexible way to scale and optimize your resource consumption. But there is a known issue with capacity planning when you deploy DaemonSets. In this guide, I will present the issue and explain how to avoid it by using Priority Class.

                                                      What is a DaemonSet?

                                                      A DaemonSet in Kubernetes is a specialized controller used to ensure that a copy of a particular pod runs on all nodes in a cluster. It is particularly useful for deploying background tasks or system-level services that need to run on every node, such as log collectors, monitoring agents, or network components.

                                                      When nodes are added to the cluster, the DaemonSet automatically schedules the specified pod on the new nodes, ensuring consistent deployment across the entire infrastructure. Similarly, when nodes are removed, the DaemonSet takes care of cleaning up the pods that were running on those nodes.

                                                      This makes DaemonSets a powerful tool for maintaining uniformity and reliability in the operation of essential services across a Kubernetes cluster.

                                                      What is the problem?

                                                      There is a known issue with Karpenter and DaemonSets when scaling nodes. DaemonSets ensure a copy of a pod runs on every node, consuming additional resources that Karpenter does not consider, leading to potential resource contention and under-provisioned nodes.

                                                      This forces operators to over-provision their nodes, resulting in inefficient resource utilization and higher costs. While the Kubernetes community and Karpenter developers are working on solutions, users currently need to manually adjust resource allocations and monitor node utilization to mitigate these issues.

                                                      A way to resolve this problem is to use a Priority Class and attach it to the DaemonSet we are creating.

                                                      How to resolve it?

                                                      What is a Priority Class?

                                                      A PriorityClass in Kubernetes is a resource used to assign a priority level to pods. This resource helps the scheduler make decisions during resource contention.

                                                      • Higher-priority pods are scheduled before lower-priority ones
                                                      • In case of resource shortages, lower-priority pods may be preempted (evicted) to make room for higher-priority pods.

                                                      This ensures that critical workloads receive the necessary resources to run effectively.

                                                      Deploy a new Priority Class using Helm

                                                      I created a simple repository you can clone to follow along.

                                                      Create the karpenter-priority-class service in the Qovery environment where you want to deploy your DaemonSet by following this documentation and these values:

                                                      • General:
                                                        • Service name: karpenter-priority-class
                                                        • Source:
                                                          • Helm source: Git Provider
                                                          • Git repository: Github (Change if you are not using GitHub)
                                                          • Repository: Baalooos/karpenter-daemonset-priority-class (Replace by the name of your repository)
                                                          • Branch: main
                                                          • Root application path: /
                                                          • Allow cluster-wide resources ✔️

                                                      Click on Continue

                                                      • Values override as file:
                                                        • File source: Git repository
                                                        • Git repository: Github (Change if you are not using GitHub)
                                                        • Repository: Baalooos/karpenter-daemonset-priority-class (Replace by the name of your repository)
                                                        • Branch: main
                                                        • Override path: /values.yaml

                                                      Then, you can:

                                                      • deploy this helm service to add the priority class on your cluster
                                                      • Modify your DaemonSet configuration to use the new priority class an redeploy it

                                                      Conclusion

                                                      Even if Karpenter is a great way of reducing your AWS bill, sometimes you will have to do some manual lifting. This issue is a good example. A single Priority Class is enough to avoid a complex resource allocation problem.

                                                      +
                                                      + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/guides/advanced/deploy-external-services/index.html b/guides/advanced/deploy-external-services/index.html index af898343e9..3af73d3519 100644 --- a/guides/advanced/deploy-external-services/index.html +++ b/guides/advanced/deploy-external-services/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 023e328def..eb898d5212 100644 --- a/guides/advanced/deploy-frontend/index.html +++ b/guides/advanced/deploy-frontend/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 bb95ce8c7d..362ec89232 100644 --- a/guides/advanced/helm-chart/index.html +++ b/guides/advanced/helm-chart/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                      Stats
                                                      1 min read
                                                      Updated
                                                      - + - + - + - + - + - + - + - + diff --git a/guides/advanced/index.html b/guides/advanced/index.html index 3612b40749..dc4385c481 100644 --- a/guides/advanced/index.html +++ b/guides/advanced/index.html @@ -24,104 +24,108 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + +
                                                      - +
                                                      - + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/guides/advanced/microservices/index.html b/guides/advanced/microservices/index.html index 21178585ed..0deb186c00 100644 --- a/guides/advanced/microservices/index.html +++ b/guides/advanced/microservices/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 554c21b1dc..0c34c4cff9 100644 --- a/guides/advanced/migration/index.html +++ b/guides/advanced/migration/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 b7586f2496..e58af200dd 100644 --- a/guides/advanced/monitoring/index.html +++ b/guides/advanced/monitoring/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 6ff5444cf1..75da67fd13 100644 --- a/guides/advanced/monorepository/index.html +++ b/guides/advanced/monorepository/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 d9efb15cbd..07bc6c9155 100644 --- a/guides/advanced/production/index.html +++ b/guides/advanced/production/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 39a634bbc3..bd49188f45 100644 --- a/guides/advanced/seed-database/index.html +++ b/guides/advanced/seed-database/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 aee8698626..77211aecfb 100644 --- a/guides/advanced/terraform/index.html +++ b/guides/advanced/terraform/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 2c72f79133..9d84dd20f7 100644 --- a/guides/advanced/use-preview-environments/index.html +++ b/guides/advanced/use-preview-environments/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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/getting-started/create-a-database/index.html b/guides/getting-started/create-a-database/index.html index 9dc22cae9c..ec7dd89c09 100644 --- a/guides/getting-started/create-a-database/index.html +++ b/guides/getting-started/create-a-database/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 ed1dd56801..e2514eb9d3 100644 --- a/guides/getting-started/debugging/index.html +++ b/guides/getting-started/debugging/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 our forum

                                                      - + - + - + - + - + - + - + - + diff --git a/guides/getting-started/deploy-your-first-application/index.html b/guides/getting-started/deploy-your-first-application/index.html index 3dd2437f4c..0bfcebb35f 100644 --- a/guides/getting-started/deploy-your-first-application/index.html +++ b/guides/getting-started/deploy-your-first-application/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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

                                                        If you did not install Qovery yet, follow this documentation.

                                                      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 5da75e3ae8..50cef06c4d 100644 --- a/guides/getting-started/index.html +++ b/guides/getting-started/index.html @@ -24,29 +24,29 @@ - + - + - + - + - + - + - + - + - + - + - + - + @@ -57,29 +57,29 @@ - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/guides/getting-started/managing-environment-variables/index.html b/guides/getting-started/managing-environment-variables/index.html index d1f0f8faf9..2a70acf55e 100644 --- a/guides/getting-started/managing-environment-variables/index.html +++ b/guides/getting-started/managing-environment-variables/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 f86782f1ac..aa3e251750 100644 --- a/guides/getting-started/setting-custom-domain/index.html +++ b/guides/getting-started/setting-custom-domain/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 our forum or on Intercom depending on your support plan.

                                                      - + - + - + - + - + - + - + - + diff --git a/guides/index.html b/guides/index.html index 0e1077a807..62a190eb22 100644 --- a/guides/index.html +++ b/guides/index.html @@ -24,316 +24,320 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + +
                                                      -

                                                      Qovery Guides

                                                      Thoughtful guides to help you get the most out of Qovery. Created and curated by the Qovery team.

                                                      Installation Guide

                                                      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 JupyterHub using Helm

                                                      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

                                                      GitOps with Qovery

                                                      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 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

                                                      Monitor and reduce Kubernetes spend with Kubecost

                                                      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
                                                      +

                                                      Qovery Guides

                                                      Thoughtful guides to help you get the most out of Qovery. Created and curated by the Qovery team.

                                                      Installation Guide

                                                      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 JupyterHub using Helm

                                                      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

                                                      GitOps with Qovery

                                                      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 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

                                                      Monitor and reduce Kubernetes spend with Kubecost

                                                      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/installation-guide/guide-amazon-web-services/index.html b/guides/installation-guide/guide-amazon-web-services/index.html index e41dcfced5..774fd0c427 100644 --- a/guides/installation-guide/guide-amazon-web-services/index.html +++ b/guides/installation-guide/guide-amazon-web-services/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                      Stats
                                                      1 min read
                                                      Updated
                                                      - + - + - + - + - + - + - + - + diff --git a/guides/installation-guide/guide-google-cloud-platform/index.html b/guides/installation-guide/guide-google-cloud-platform/index.html index 3e89508396..b13193153c 100644 --- a/guides/installation-guide/guide-google-cloud-platform/index.html +++ b/guides/installation-guide/guide-google-cloud-platform/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                      Stats
                                                      1 min read
                                                      Updated
                                                      - + - + - + - + - + - + - + - + diff --git a/guides/installation-guide/guide-kubernetes/index.html b/guides/installation-guide/guide-kubernetes/index.html index 7b025d1480..37cd14a334 100644 --- a/guides/installation-guide/guide-kubernetes/index.html +++ b/guides/installation-guide/guide-kubernetes/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                      Stats
                                                      1 min read
                                                      Updated
                                                      - + - + - + - + - + - + - + - + diff --git a/guides/installation-guide/guide-microsoft-azure/index.html b/guides/installation-guide/guide-microsoft-azure/index.html index 084f068085..1742a775b0 100644 --- a/guides/installation-guide/guide-microsoft-azure/index.html +++ b/guides/installation-guide/guide-microsoft-azure/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                      Stats
                                                      1 min read
                                                      Updated
                                                      - + - + - + - + - + - + - + - + diff --git a/guides/installation-guide/guide-scaleway/index.html b/guides/installation-guide/guide-scaleway/index.html index cacb5546c1..1db0ca4b56 100644 --- a/guides/installation-guide/guide-scaleway/index.html +++ b/guides/installation-guide/guide-scaleway/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                      Stats
                                                      1 min read
                                                      Updated
                                                      - + - + - + - + - + - + - + - + diff --git a/guides/installation-guide/index.html b/guides/installation-guide/index.html index 3c7db08153..955b3898fc 100644 --- a/guides/installation-guide/index.html +++ b/guides/installation-guide/index.html @@ -24,31 +24,31 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -57,31 +57,31 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/database-postgresql/index.html b/guides/tags/database-postgresql/index.html index 7a2ea7dd87..e0c3463afa 100644 --- a/guides/tags/database-postgresql/index.html +++ b/guides/tags/database-postgresql/index.html @@ -24,29 +24,29 @@ - + - + - + - + - + - + - + - + - + - + - + - + @@ -55,29 +55,29 @@ - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/framework-rails/index.html b/guides/tags/framework-rails/index.html index fc1ab62a52..a439c796e6 100644 --- a/guides/tags/framework-rails/index.html +++ b/guides/tags/framework-rails/index.html @@ -24,23 +24,23 @@ - + - + - + - + - + - + - + - + - + @@ -49,23 +49,23 @@ - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/index.html b/guides/tags/index.html index 2012b5c771..7596032c63 100644 --- a/guides/tags/index.html +++ b/guides/tags/index.html @@ -24,44 +24,44 @@ - + - + - + - + - + - + - + - +
                                                      - +
                                                      - + - + - + - + - + - + - + - + diff --git a/guides/tags/installation-guide-aws/index.html b/guides/tags/installation-guide-aws/index.html index 5baf111fde..97f51b23de 100644 --- a/guides/tags/installation-guide-aws/index.html +++ b/guides/tags/installation-guide-aws/index.html @@ -24,96 +24,100 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + +
                                                      - +
                                                      - + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/installation-guide-azure/index.html b/guides/tags/installation-guide-azure/index.html index 323361f706..b33b6961b6 100644 --- a/guides/tags/installation-guide-azure/index.html +++ b/guides/tags/installation-guide-azure/index.html @@ -24,23 +24,23 @@ - + - + - + - + - + - + - + - + - + @@ -49,23 +49,23 @@ - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/installation-guide-gcp/index.html b/guides/tags/installation-guide-gcp/index.html index 63b4b62a29..740db7092e 100644 --- a/guides/tags/installation-guide-gcp/index.html +++ b/guides/tags/installation-guide-gcp/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -49,21 +49,21 @@ - + - + - + - + - + - + - + - + diff --git a/guides/tags/installation-guide-kubernetes/index.html b/guides/tags/installation-guide-kubernetes/index.html index 8280e4ab52..3e6f02be16 100644 --- a/guides/tags/installation-guide-kubernetes/index.html +++ b/guides/tags/installation-guide-kubernetes/index.html @@ -24,23 +24,23 @@ - + - + - + - + - + - + - + - + - + @@ -49,23 +49,23 @@ - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/installation-guide-scaleway/index.html b/guides/tags/installation-guide-scaleway/index.html index 1b57f45557..fd2512364b 100644 --- a/guides/tags/installation-guide-scaleway/index.html +++ b/guides/tags/installation-guide-scaleway/index.html @@ -24,23 +24,23 @@ - + - + - + - + - + - + - + - + - + @@ -49,23 +49,23 @@ - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/language-javascript/index.html b/guides/tags/language-javascript/index.html index 0aeda0a85a..ab7872c0ac 100644 --- a/guides/tags/language-javascript/index.html +++ b/guides/tags/language-javascript/index.html @@ -24,25 +24,25 @@ - + - + - + - + - + - + - + - + - + - + @@ -51,25 +51,25 @@ - + - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/language-kotlin/index.html b/guides/tags/language-kotlin/index.html index 1efc25de02..78ada16e04 100644 --- a/guides/tags/language-kotlin/index.html +++ b/guides/tags/language-kotlin/index.html @@ -24,25 +24,25 @@ - + - + - + - + - + - + - + - + - + - + @@ -51,25 +51,25 @@ - + - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/language-ruby/index.html b/guides/tags/language-ruby/index.html index e300432463..893a10fb05 100644 --- a/guides/tags/language-ruby/index.html +++ b/guides/tags/language-ruby/index.html @@ -24,23 +24,23 @@ - + - + - + - + - + - + - + - + - + @@ -49,23 +49,23 @@ - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/language-rust/index.html b/guides/tags/language-rust/index.html index c59ac7c07b..6f7d56d25b 100644 --- a/guides/tags/language-rust/index.html +++ b/guides/tags/language-rust/index.html @@ -24,25 +24,25 @@ - + - + - + - + - + - + - + - + - + - + @@ -53,25 +53,25 @@ - + - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/technology-docker/index.html b/guides/tags/technology-docker/index.html index f1850d068b..cbfddaaad1 100644 --- a/guides/tags/technology-docker/index.html +++ b/guides/tags/technology-docker/index.html @@ -24,23 +24,23 @@ - + - + - + - + - + - + - + - + - + @@ -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 b2e992435a..b7ab1161b3 100644 --- a/guides/tags/technology-github/index.html +++ b/guides/tags/technology-github/index.html @@ -24,23 +24,23 @@ - + - + - + - + - + - + - + - + - + @@ -49,23 +49,23 @@ - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/technology-helm/index.html b/guides/tags/technology-helm/index.html index eb5c41165e..44f98a761d 100644 --- a/guides/tags/technology-helm/index.html +++ b/guides/tags/technology-helm/index.html @@ -24,23 +24,23 @@ - + - + - + - + - + - + - + - + - + @@ -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 8d6b3af25e..86abec6940 100644 --- a/guides/tags/technology-qovery/index.html +++ b/guides/tags/technology-qovery/index.html @@ -24,212 +24,216 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + +
                                                      -

                                                      41 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 JupyterHub using Helm

                                                      read now
                                                      tutorial

                                                      Deploy Temporal on Kubernetes

                                                      read now
                                                      tutorial

                                                      Getting Started with Preview Environments on AWS

                                                      read now
                                                      tutorial

                                                      GitOps with Qovery

                                                      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 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
                                                      tutorial

                                                      Monitor and reduce Kubernetes spend with Kubecost

                                                      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
                                                      +

                                                      42 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 a DaemonSet in a Karpenter context

                                                      read now
                                                      advanced

                                                      Deploy API Gateway

                                                      read now
                                                      advanced

                                                      Deploy External Services

                                                      read now
                                                      tutorial

                                                      Deploy JupyterHub using Helm

                                                      read now
                                                      tutorial

                                                      Deploy Temporal on Kubernetes

                                                      read now
                                                      tutorial

                                                      Getting Started with Preview Environments on AWS

                                                      read now
                                                      tutorial

                                                      GitOps with Qovery

                                                      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 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
                                                      tutorial

                                                      Monitor and reduce Kubernetes spend with Kubecost

                                                      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 35956825ae..71eb27be19 100644 --- a/guides/tags/technology-terraform/index.html +++ b/guides/tags/technology-terraform/index.html @@ -24,23 +24,23 @@ - + - + - + - + - + - + - + - + - + @@ -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 0234534683..be162afcd8 100644 --- a/guides/tags/type-guide/index.html +++ b/guides/tags/type-guide/index.html @@ -24,71 +24,71 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -97,71 +97,71 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/guides/tags/type-tutorial/index.html b/guides/tags/type-tutorial/index.html index 351a65d778..c07fbb0cd0 100644 --- a/guides/tags/type-tutorial/index.html +++ b/guides/tags/type-tutorial/index.html @@ -24,216 +24,220 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + +
                                                      -

                                                      42 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 JupyterHub using Helm

                                                      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

                                                      GitOps with Qovery

                                                      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 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

                                                      Monitor and reduce Kubernetes spend with Kubecost

                                                      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
                                                      +

                                                      43 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
                                                      advanced

                                                      Deploy a DaemonSet in a Karpenter context

                                                      read now
                                                      tutorial

                                                      Deploy JupyterHub using Helm

                                                      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

                                                      GitOps with Qovery

                                                      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 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

                                                      Monitor and reduce Kubernetes spend with Kubecost

                                                      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 a40c695489..526db73028 100644 --- a/guides/tutorial/aws-sqs-lambda-with-qovery/index.html +++ b/guides/tutorial/aws-sqs-lambda-with-qovery/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 c2bf56d48b..304895e9b4 100644 --- a/guides/tutorial/aws-vpc-peering-with-qovery/index.html +++ b/guides/tutorial/aws-vpc-peering-with-qovery/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 c5790b620d..b42090eb16 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 e583105227..548b9c5426 100644 --- a/guides/tutorial/build-e2e-testing-ephemeral-environments/index.html +++ b/guides/tutorial/build-e2e-testing-ephemeral-environments/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 e130f7e195..714a957148 100644 --- a/guides/tutorial/cloudwatch-integration/index.html +++ b/guides/tutorial/cloudwatch-integration/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -53,21 +53,21 @@
                                                      elasticsearch:
                                                      enabled: false

                                                      You can take a look at additional configuration options on the AWS provided chart

                                                      Now get to the last step and just Create the service on Qovery.

                                                      Store the AWS Secrets as Qovery secrets

                                                      In the previous step we have assigned the macro qovery.env.qovery.env.AWS_ACCESS_KEY and qovery.env.AWS_SECRET_ACCESS_KEY to the AWS secrets. In this step we will create these secrets within the Qovery console.

                                                      • Open the service overview of the created Datadog service
                                                      • Enter the Variables section
                                                      • Add a new Variable with:
                                                        • Variable = AWS_SECRET_ACCESS_KEY
                                                        • Value = <your_SECRET_ACCESS_KEY>
                                                        • Scope = Service (so that it is accessible only to this service)
                                                        • Secret variable ✔️
                                                      • Add a new Variable with:
                                                        • Variable = AWS_ACCESS_KEY
                                                        • Value = <your_ACCESS_KEY>
                                                        • Scope = Service (so that it is accessible only to this service)
                                                        • Secret variable ✔️

                                                      If you need more information on how to manage your environment variables, have a look at this documentation

                                                      Deploy your chart

                                                      Open the Play button and trigger the deployment of your chart.

                                                      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 856cddac19..0067382790 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 a3653931b2..abf4c7a092 100644 --- a/guides/tutorial/create-a-playground-environment-on-aws/index.html +++ b/guides/tutorial/create-a-playground-environment-on-aws/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 10982c3f05..bc39951abd 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 2ad80152c7..6b33cd4e0d 100644 --- a/guides/tutorial/customizing-preview-url-with-qovery-cli/index.html +++ b/guides/tutorial/customizing-preview-url-with-qovery-cli/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 cf7efcf1f6..69f081264f 100644 --- a/guides/tutorial/data-seeding-in-postgres/index.html +++ b/guides/tutorial/data-seeding-in-postgres/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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-jupyterhub-qovery/index.html b/guides/tutorial/deploy-jupyterhub-qovery/index.html index 112ca4086d..fb1dd9de69 100644 --- a/guides/tutorial/deploy-jupyterhub-qovery/index.html +++ b/guides/tutorial/deploy-jupyterhub-qovery/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -47,21 +47,21 @@

                                                      Deploy JupyterHub using Helm

                                                      How to deploy JupyterHub on Qovery using the official Helm chart.

                                                      JupyterHub is an easy way to interact with a computing environment through a webpage. It provides a standardized way to serve Jupyter Notebooks for multiple users. Pairing it with Kubernetes and Qovery makes it easier to manage and scale.

                                                      Installation

                                                      The easiest way to deploy JupyterHub is using the official Helm Chart. It will create all the resources you need to run JupyterHub.

                                                      For more information, the official documentation is available here.

                                                      1. Add the JupyterHub helm repository

                                                        Add the JupyterHub helm repository in your Qovery settings by following this documentation

                                                        • Repository name: JupyterHub
                                                        • Kind: HTTPS
                                                        • Repository URL: https://hub.jupyter.org/helm-chart/
                                                      2. Create the JupyterHub service within Qovery

                                                        Create the JupyterHub service in the Qovery environment of your choice (preferably within a dedicated JupyterHub project) by following this documentation and these values:

                                                        • General:
                                                          • Application name: JupyterHub
                                                          • Source:
                                                            • Helm source: Helm repository
                                                            • Repository: JupyterHub (the name given during the JupyterHub helm repository added in the previous step)
                                                            • Chart name: jupyterhub
                                                            • Version: 3.3.7 (this is the version we used for this setup, update it based on the chosen version)
                                                            • Allow cluster-wide resources ✔️
                                                        • Values
                                                          • Values override as file:
                                                          • File source: Raw YAML
                                                          • Raw YAML:
                                                        fullnameOverride: "jupyterhub"
                                                        proxy:
                                                        service:
                                                        type: ClusterIP

                                                        There are many other values you can set to modify the JupyterHub behavior. For advanced usage, check: JupyterHub Customization

                                                        Now get to the last step and Create the service on Qovery.

                                                      3. Add Network configuration

                                                        In the previous step, we created the JupyterHub service. In this step, we will update its configuration to make it available on the public network (through Qovery Nginx Ingress).

                                                        • Open the JupyterHub service details
                                                        • Enter the Settings section
                                                        • Click on Networking
                                                        • Add a new Port with:
                                                          • Service name: jupyterhub-proxy-public
                                                          • Service port: 80
                                                          • Select protocol: HTTP
                                                          • External port: 443
                                                          • Port name: jupyterhub-proxy-public-p80

                                                        If you need more information on how to manage your ports, have a look at this

                                                      4. Deploy your chart

                                                        Open the Play button and trigger the deployment of your chart.

                                                        JupyterHub - Deploy

                                                      5. Access JupyterHub

                                                        You can click the Link button to access JupyterHub on your cluster.

                                                        JupyterHub - Link

                                                        Now you can login to the webUI and start playing with Jupyter Notebooks.

                                                      Conclusion

                                                      JupyterHub is running on your Qovery cluster. This is a simple installation and you should try to customize it according to your needs. You can also check theAdminstrator Guideto better understand how it works.

                                                      - + - + - + - + - + - + - + - + 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 cb228d22b3..5a2986f466 100644 --- a/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq/index.html +++ b/guides/tutorial/deploy-rails-with-postgresql-and-sidekiq/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 df38120e48..3e805a494e 100644 --- a/guides/tutorial/deploy-temporal-on-kubernetes/index.html +++ b/guides/tutorial/deploy-temporal-on-kubernetes/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 c22f22fb97..2d2d150e9b 100644 --- a/guides/tutorial/generate-qovery-api-client/index.html +++ b/guides/tutorial/generate-qovery-api-client/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 df70e49589..b814400bf5 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 c00df01ef7..343cddf1ed 100644 --- a/guides/tutorial/github-organization-repository-access/index.html +++ b/guides/tutorial/github-organization-repository-access/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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/gitops-with-qovery/index.html b/guides/tutorial/gitops-with-qovery/index.html index 108b075253..42b0dc41ee 100644 --- a/guides/tutorial/gitops-with-qovery/index.html +++ b/guides/tutorial/gitops-with-qovery/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -92,21 +92,21 @@ You can check the Qovery Audit Logs to see the changes made by the Terraform configuration.

                                                      How to manage the Terraform state?

                                                      Like in the example above, we recommend using a remote Terraform backend to store the state. This way, you can share the state between your team members and have a history of the changes. You can use the Hashicorp Cloud Platform or any other Terraform backend you want.

                                                      How to connect to get Terraform Cloud state?

                                                      Create a backend.tf file in your Terraform configuration with the following content:

                                                      backend.tf
                                                      terraform {
                                                      backend "remote" {
                                                      hostname = "app.terraform.io"
                                                      organization = "Qovery"
                                                      workspaces {
                                                      name = "qovery-gitops"
                                                      }
                                                      }
                                                      }

                                                      Refer to this documentation

                                                      How to integrate tests?

                                                      You can use the Qovery API to get the resources URLs and integrate them in your CI/CD. For example, you can get the URL of the application and use it in your tests. Look at this guide on how to run E2E tests with Qovery and GitHub Actions.

                                                      Conclusion

                                                      In this tutorial, you learned how to do GitOps with Qovery and the Qovery Terraform provider. You defined all the Qovery resources in a Terraform configuration, tested it locally, pushed it to a GitHub repository, used GitHub Actions to review and apply the Terraform configuration, and checked the Qovery console to see the resources created.

                                                      If you have any questions or need help, feel free to ask in the Qovery Community Forum.

                                                      - + - + - + - + - + - + - + - + diff --git a/guides/tutorial/grafana-install/index.html b/guides/tutorial/grafana-install/index.html index 80b1974342..cad9730c44 100644 --- a/guides/tutorial/grafana-install/index.html +++ b/guides/tutorial/grafana-install/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 db6083508f..d45620b050 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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. You can retrieve the Kubeconfig of your cluster directly from the Qovery interface by following the procedure "Get your cluster kubeconfig file" within this section.

                                                    • 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 273844f361..457f303c10 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 ed93205748..9f8aeabdae 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 22cb050b70..1491221b28 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 fbe7e3c598..9e4bc879a5 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 d7c6154500..4720348805 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 cb72fa377a..e53f0f1084 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 10a36da1a2..9ce7371e1e 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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-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 2ee3dbd697..9ce8dc835a 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                      Stats
                                                      1 min read
                                                      Updated
                                                      - + - + - + - + - + - + - + - + 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 1e33556061..694419a0ff 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 be5a2b8376..b7e438e74d 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 22ba0c1239..27472558bf 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 1923c01abb..bc029a9c2f 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 6744923c92..2981d9aeed 100644 --- a/guides/tutorial/how-to-write-a-dockerfile/index.html +++ b/guides/tutorial/how-to-write-a-dockerfile/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 df3b2d9a24..45c2914060 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 86278c5e6f..0f562b35fe 100644 --- a/guides/tutorial/index.html +++ b/guides/tutorial/index.html @@ -24,107 +24,107 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -133,107 +133,107 @@

                                                      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 JupyterHub using Helm

                                                      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

                                                      GitOps with Qovery

                                                      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 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

                                                      Monitor and reduce Kubernetes spend with Kubecost

                                                      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 58502b7a18..a63f0bfbbc 100644 --- a/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/index.html +++ b/guides/tutorial/kubernetes-observability-and-monitoring-with-datadog/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@ Datadog is one of the leading platforms for monitoring and observability, and it's pretty easy to integrate it with Qovery.

                                                      Installation

                                                      In this tutorial, we will install the Datadog agent on a Qovery cluster to gather metrics about infrastructure and applications.

                                                      1. Add the Datadog helm repository

                                                        Add the Datadog helm repository in your Qovery settings by following this documentation

                                                        • Repository name: Datadog
                                                        • Kind: HTTPS
                                                        • Repository URL: https://helm.datadoghq.com
                                                      2. Create the datadog service within Qovery

                                                        Create the Datadog helm service in the Qovery environment of your choice (preferrably within a dedicated Tooling project) by following this documentation and these values:

                                                        • General:
                                                          • Application name: Datadog
                                                          • Source:
                                                            • Helm source: Helm repository
                                                            • Repository: Datadog (the name given during the datadog helm repository added in the previous step)
                                                            • Chart name: datadog
                                                            • Version: 3.49.5 (this is the version we used for this setup, update it based on the chosen version)
                                                            • Allow cluster-wide resources ✔️
                                                        • Values
                                                          • Values override as file:
                                                          • File source: Raw YAML
                                                          • Raw YAML:
                                                        # The following YAML contains the minimum configuration required to deploy the Datadog Agent
                                                        # on your cluster. Update it accordingly to your needs
                                                        datadog:
                                                        # here we use a Qovery secret to retrieve the Datadog API Key (See next step)
                                                        apiKey: qovery.env.DD_API_KEY
                                                        # Update the site depending on where you want to store your data in Datadog
                                                        site: datadoghq.eu
                                                        # Update the cluster name with the name of your choice
                                                        clusterName: qoverycluster

                                                        There are many other values you can set and modify the Datadog agent behaviour. For advanced usage, check: https://github.com/Datadog/helm-charts/blob/main/charts/datadog/values.yaml

                                                        Now get to the last step and just Create the service on Qovery.

                                                      3. Store the Datadog API Key as secret

                                                        In the previous step we have assigned the macro qovery.env.DD_API_KEY to the API Key value. In this step we will create this secret within the Qovery console.

                                                        • Open the service overview of the created Datadog service
                                                        • Enter the Variables section
                                                        • Add a new Variable with:
                                                          • Variable = DD_API_KEY
                                                          • Value = <your_API_KEY>
                                                          • Scope = Service (so that it is accessible only to this service)
                                                          • Secret variable ✔️

                                                        Datadog - API Key

                                                        If you need more information on how to manage your environment variables, have a look at this documentation

                                                      4. Deploy your chart

                                                        Open the Play button and trigger the deployment of your chart (see point 1 in the picture below).

                                                        Datadog - Deploy

                                                        You can follow the deployment and access the deployment logs by pressing the Log button (see point 2 in the picutre above).

                                                        Once the deployment is completed, you should see the Datadog agent pods and their status directly within the Qovery console.

                                                        Datadog - Pods

                                                        You can also look at the Pod logs by pressing the Log button.

                                                      5. Verify the setup on Datadog

                                                        Access again your Datadog interface and access the Infrastructure > Containers > Kubernetes sections. You should now see the data coming from your Qovery cluster

                                                        Datadog - Console

                                                      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 717f01671f..dc66ced600 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 c7986191eb..8f8799a5d6 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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?

                                                      Absolutely, you can connect directly to your application with a shell by clicking on the Qovery cloud shell button (1):

                                                      Qovery Cloud Shell

                                                      Then you just have to select the pod (2) and the container (3).

                                                      You can also check out our CLI and the qovery shell command.

                                                      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/monitor-and-reduce-kubernetes-spend-with-kubecost/index.html b/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost/index.html index aadc17d2a8..51090adb09 100644 --- a/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost/index.html +++ b/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -47,21 +47,21 @@

                                                      Monitor and reduce Kubernetes spend with Kubecost

                                                      How to deploy Kubecost with Qovery

                                                      Goal

                                                      In this tutorial, we will install Kubecost on a Qovery cluster to monitor the Kubernetes costs

                                                      1. Add the Kubecost helm repository

                                                        Add the Kubecost helm repository in your Qovery settings by following this documentation with these values:

                                                        • Repository name: Kubecost
                                                        • Kind: HTTPS
                                                        • Repository URL: https://kubecost.github.io/cost-analyzer/
                                                      2. Deploy the Kubecost helm chart

                                                        Deploy the Kubecost helm chart in your Qovery environment by following this documentation with these values:

                                                        • General:
                                                          • Application name: Kubecost
                                                          • Source:
                                                            • Helm source: Helm repository
                                                            • Repository: Kubecost (the name given during the kubecost helm repository added in the previous step)
                                                            • Chart name: cost-analyzer
                                                            • Version: 1.108.0 (this guide works with the version 1.108.0 and that needs to be adapted if you use another version)
                                                          • Allow cluster-wide resources ✔️
                                                        • Values
                                                          • Values override as file:
                                                            • File source: Raw YAML
                                                            • Raw YAML:
                                                        kubecostToken: qovery.env.KUBECOST_TOKEN #Used only if you have a Kubecost Token

                                                        Then click on Create and Deploy

                                                      3. Expose Kubecost

                                                        Check the cost-analyzer service name in the deployment logs, example: helm-z325f0565-kubecost-cost-analyzer

                                                        Service name

                                                        Go in your helm chart settings under the Networking section and add a new port by clicking on Add port, and set these values:

                                                        • Service name: helm-z325f0565-kubecost-cost-analyzer (the service name taken from the deployment logs)
                                                        • Service port: 9090
                                                        • Select protocol: HTTP
                                                        • Port name: You can customize it or let the default port name.

                                                        Add port

                                                        Then click on Create and redeploy your helm in Qovery.

                                                        A URL will be generated to access the Kubecost frontend application:

                                                        Link

                                                      Conclusion

                                                      You now have Kubecost running on your Qovery cluster. You can check their Getting Started guide to familiarize yourself with the product: https://docs.kubecost.com/#getting-started.

                                                      - + - + - + - + - + - + - + - + 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 e47a69a098..a371248c43 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 7cc1a15a64..358c60ae81 100644 --- a/guides/tutorial/url-shortener-api-with-kotlin/index.html +++ b/guides/tutorial/url-shortener-api-with-kotlin/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 676d36dd8a..564b4aeab7 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 @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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 74d78cfad8..d93bcf75d4 100644 --- a/guides/tutorial/use-aws-iam-roles-with-qovery/index.html +++ b/guides/tutorial/use-aws-iam-roles-with-qovery/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -48,21 +48,21 @@
                                                      Stats
                                                      7 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 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 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

                                                      Deploy a service account with Helm

                                                      Qovery provides a simple Helm chart to deploy a service account on your Kubernetes cluster in a specific environment (Kubernetes namespace).

                                                      Start to create a new service, with an Helm chart:

                                                      Create Service Account

                                                      Then configure the Helm chart with the following values:

                                                      Helm chart

                                                      • Helm source: Helm repository
                                                      • Git repository: Qovery Service Account Helper
                                                      • Chart name: qovery-sa-helper
                                                      • Version: 0.1.0

                                                      Create a new help repository on phase 3, and fill the chart info:

                                                      Helm chart

                                                      • Repository name: Qovery Service Account Helper
                                                      • Kind: HTTPS
                                                      • Repository url: https://qovery.github.io/create_service_account/

                                                      Then click on Create, and the Continue button.

                                                      On the values override file, we do not need to override anything, so select None, and then click on the Continue button.

                                                      Helm chart

                                                      We then have to add 2 override arguments:

                                                      1. serviceAccount.name: the name of the service account in Kubernetes (the same name you have declared for the role in the Trusted entities policy section)
                                                      2. awsRoleArn: the ARN of the role you have created

                                                      Helm chart

                                                      Then click on the Continue button.

                                                      You can finally Create and Deploy it. If you look at the logs, you should see something like:

                                                      Helm chart

                                                      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 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 9d7ecfbae7..0907d2709a 100644 --- a/guides/tutorial/working-with-git-submodules/index.html +++ b/guides/tutorial/working-with-git-submodules/index.html @@ -24,21 +24,21 @@ - + - + - + - + - + - + - + - + @@ -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/index.html b/index.html index fa6efea5cd..2605c2c949 100644 --- a/index.html +++ b/index.html @@ -24,19 +24,19 @@ - + - + - + - + - + - + - + @@ -45,19 +45,19 @@

                                                      Qovery Hub Resources

                                                      Qovery is a DevOps Automation Platform that eliminates your DevOps hiring needs. Provision and maintain a secure and compliant infrastructure in hours - not months!.
                                                      - + - + - + - + - + - + - + diff --git a/mailing_list/index.html b/mailing_list/index.html index d535c7068d..9d19066b06 100644 --- a/mailing_list/index.html +++ b/mailing_list/index.html @@ -20,13 +20,13 @@ - + - + - + - + @@ -35,13 +35,13 @@ - + - + - + - + diff --git a/main.9e3caed0.js b/main.9e3caed0.js deleted file mode 100644 index d586e85fe7..0000000000 --- a/main.9e3caed0.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see main.9e3caed0.js.LICENSE.txt */ -(window.webpackJsonp=window.webpackJsonp||[]).push([[291],[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(!u)for(;d--;d)a.unshift("..");!u||""===a[0]||a[0]&&r(a[0])||a.unshift("");var g=a.join("/");return n&&"/"!==g.substr(-1)&&(g+="/"),g};function s(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=s(t),r=s(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},u=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(s){throw s instanceof URIError?new URIError('Pathname "'+i.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):s}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),s=n(30),l=function(e,t,n){var u,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(u in g&&(n=t),n)d=((c=!f&&v&&void 0!==v[u])?v:n)[u],p=b&&c?s(d,o):h&&"function"==typeof d?s(Function.call,d):d,v&&a(v,u,d,e&l.U),y[u]!=d&&i(y,u,p),h&&w[u]!=d&&(w[u]=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"),s=n(104),l=(""+s).split("toString");n(17).inspectSource=function(e){return s.call(e)},(e.exports=function(e,t,n,s){var u="function"==typeof n;u&&(i(n,"name")||r(n,"name",t)),e[t]!==n&&(u&&(i(n,a)||r(n,a,e[t]?""+e[t]:l.join(String(t)))),e===o?e[t]=n:s?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]||s.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 2024 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:{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/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"},"installation-guide":{children:{},description:"Install Qovery on your technical stack.",guides:[{author_github:"https://github.com/evoxmusic",description:null,id:"/installation-guide/guide-amazon-web-services",last_modified_on:null,path:"website/guides/installation-guide/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:"/installation-guide/guide-kubernetes",last_modified_on:null,path:"website/guides/installation-guide/guide-kubernetes.md",series_position:null,title:"Install Qovery on your Kubernetes cluster"},{author_github:"https://github.com/evoxmusic",description:null,id:"/installation-guide/guide-microsoft-azure",last_modified_on:null,path:"website/guides/installation-guide/guide-microsoft-azure.md",series_position:null,title:"Install Qovery on your Microsoft Azure account"},{author_github:"https://github.com/evoxmusic",description:null,id:"/installation-guide/guide-scaleway",last_modified_on:null,path:"website/guides/installation-guide/guide-scaleway.md",series_position:null,title:"Install Qovery on your Scaleway account"},{author_github:"https://github.com/evoxmusic",description:null,id:"/installation-guide/guide-google-cloud-platform",last_modified_on:null,path:"website/guides/installation-guide/guide-google-cloud-platform.md",series_position:null,title:"Install Qovery your Google Cloud Platform account"}],name:"installation-guide",series:!1,title:"Installation Guide"},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/baalooos",description:null,id:"/tutorial/deploy-jupyterhub-qovery",last_modified_on:null,path:"website/guides/tutorial/deploy-jupyterhub-qovery.md",series_position:null,title:"Deploy JupyterHub using Helm"},{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/evoxmusic",description:null,id:"/tutorial/gitops-with-qovery",last_modified_on:null,path:"website/guides/tutorial/gitops-with-qovery.md",series_position:null,title:"GitOps with Qovery"},{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/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/acarranoqovery",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/monitor-and-reduce-kubernetes-spend-with-kubecost",last_modified_on:null,path:"website/guides/tutorial/monitor-and-reduce-kubernetes-spend-with-kubecost.md",series_position:null,title:"Monitor and reduce Kubernetes spend with Kubecost"},{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:{},installation_guides:[{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"},{dark_logo_path:"/img/logos/kubernetes_white.svg",logo_path:"/img/logos/kubernetes.svg",name:"kubernetes"}],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:[],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"},{avatar:"https://github.com/acarranoqovery.png",bio:'Alessandro is a Lead Product Manager at Qovery.',github:"https://github.com/acarranoqovery",id:"acarranoqovery",keybase:"https://keybase.io/acarranoqovery",name:"Alessandro Carrano"},{avatar:"https://github.com/baalooos.png",bio:'Charles-Edouard is Technical Account Manager at Qovery.',github:"https://github.com/baalooos",id:"cegagnaire",keybase:"https://keybase.io/baalooos",name:"Charles-Edouard Gagnaire"}],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:"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 2024 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:!0},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 s})),n.d(t,"b",(function(){return l}));var o=n(3),r=n(1),i=n(0),a=n.n(i);function s(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&&s(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(s){}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),s=n(11),l=n(24),u=n(2),c=u("iterator"),d=u("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":"9fe26b56"},{"content":"946bf02d"},{"content":"73d96058"},{"content":"ff2506fd"},{"content":"86a0e6ef"},{"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":"3ecdd190"},{"content":"50bab564"},{"content":"2cb76395"},{"content":"3088ad98"},{"content":"dfcfd2f3"},{"content":"df1c18d8"},{"content":"8f02216a"},{"content":"1b633bfd"},{"content":"bc592dc7"},{"content":"acaf40e9"},{"content":"5b95bed2"},{"content":"3986a7a9"},{"content":"de0a75d9"},{"content":"bdd6d8c6"},{"content":"b565c464"},{"content":"40ec3bc1"},{"content":"fb1d0a83"},{"content":"9107e302"},{"content":"a1fea8fb"},{"content":"e06f2af5"},{"content":"8d146bfd"},{"content":"bbfbe73c"},{"content":"60296d59"},{"content":"e1becc8e"},{"content":"b5eab6bb"},{"content":"072d4c63"},{"content":"dea3d534"},{"content":"6ce627d6"},{"content":"e5b9b0aa"},{"content":"e1e1580b"},{"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/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/installation-guide":{"component":"d9deea5f","items":[{"content":"9fe26b56"},{"content":"946bf02d"},{"content":"73d96058"},{"content":"ff2506fd"},{"content":"86a0e6ef"}],"metadata":"6852f5b3"},"/guides/installation-guide/guide-amazon-web-services":{"component":"1c13b173","content":"225ad2ad"},"/guides/installation-guide/guide-google-cloud-platform":{"component":"1c13b173","content":"9b266254"},"/guides/installation-guide/guide-kubernetes":{"component":"1c13b173","content":"dffbf523"},"/guides/installation-guide/guide-microsoft-azure":{"component":"1c13b173","content":"f6a16982"},"/guides/installation-guide/guide-scaleway":{"component":"1c13b173","content":"7cc8f9b8"},"/guides/tags":{"component":"3116c1fa","tags":"a81fb19d"},"/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/installation-guide-aws":{"component":"004ec9e5","items":[{"content":"9fe26b56"},{"content":"a156f6a6"},{"content":"3e6b1f84"},{"content":"1b633bfd"},{"content":"3986a7a9"},{"content":"de0a75d9"},{"content":"bdd6d8c6"},{"content":"a1fea8fb"},{"content":"6ce627d6"},{"content":"c8223350"},{"content":"cbb976f4"},{"content":"0c18cf89"}],"metadata":"c539337b"},"/guides/tags/installation-guide-azure":{"component":"004ec9e5","items":[{"content":"86a0e6ef"}],"metadata":"73709b64"},"/guides/tags/installation-guide-gcp":{"component":"004ec9e5","items":[{"content":"946bf02d"}],"metadata":"1e2e1850"},"/guides/tags/installation-guide-kubernetes":{"component":"004ec9e5","items":[{"content":"ff2506fd"}],"metadata":"7e863710"},"/guides/tags/installation-guide-scaleway":{"component":"004ec9e5","items":[{"content":"73d96058"}],"metadata":"a601bb0b"},"/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/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":"3ecdd190"},{"content":"2cb76395"},{"content":"3088ad98"},{"content":"dfcfd2f3"},{"content":"df1c18d8"},{"content":"bc592dc7"},{"content":"acaf40e9"},{"content":"5b95bed2"},{"content":"fb1d0a83"},{"content":"9107e302"},{"content":"e06f2af5"},{"content":"8d146bfd"},{"content":"60296d59"},{"content":"e1becc8e"},{"content":"b5eab6bb"},{"content":"dea3d534"},{"content":"e5b9b0aa"},{"content":"e1e1580b"},{"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":"9fe26b56"},{"content":"946bf02d"},{"content":"73d96058"},{"content":"ff2506fd"},{"content":"86a0e6ef"},{"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":"f11e9a8e"},"/guides/tags/type-tutorial":{"component":"004ec9e5","items":[{"content":"a156f6a6"},{"content":"56c0a343"},{"content":"89caf623"},{"content":"967beaa8"},{"content":"1a6d3985"},{"content":"ff0cde69"},{"content":"cbcbf0e3"},{"content":"3ecdd190"},{"content":"50bab564"},{"content":"2cb76395"},{"content":"3088ad98"},{"content":"dfcfd2f3"},{"content":"df1c18d8"},{"content":"1b633bfd"},{"content":"bc592dc7"},{"content":"acaf40e9"},{"content":"5b95bed2"},{"content":"3986a7a9"},{"content":"de0a75d9"},{"content":"bdd6d8c6"},{"content":"b565c464"},{"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":"e1e1580b"},{"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":"3ecdd190"},{"content":"50bab564"},{"content":"2cb76395"},{"content":"3088ad98"},{"content":"dfcfd2f3"},{"content":"df1c18d8"},{"content":"1b633bfd"},{"content":"bc592dc7"},{"content":"acaf40e9"},{"content":"5b95bed2"},{"content":"3986a7a9"},{"content":"de0a75d9"},{"content":"bdd6d8c6"},{"content":"b565c464"},{"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":"e1e1580b"},{"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-jupyterhub-qovery":{"component":"1c13b173","content":"abbfd6bd"},"/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/gitops-with-qovery":{"component":"1c13b173","content":"dfb1c803"},"/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-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/monitor-and-reduce-kubernetes-spend-with-kubecost":{"component":"1c13b173","content":"4b542f80"},"/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/install-qovery/aws":{"component":"17896441","content":"4132998e"},"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery":{"component":"17896441","content":"e862b20f"},"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/create-credentials":{"component":"17896441","content":"04b748dc"},"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/faq":{"component":"17896441","content":"48dbd876"},"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/infrastructure":{"component":"17896441","content":"c8dfbbe7"},"/docs/getting-started/install-qovery/aws/cluster-managed-by-qovery/quickstart":{"component":"17896441","content":"099598c5"},"/docs/getting-started/install-qovery/aws/self-managed-cluster":{"component":"17896441","content":"ab1ec509"},"/docs/getting-started/install-qovery/azure":{"component":"17896441","content":"115eba8e"},"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery":{"component":"17896441","content":"0f632e24"},"/docs/getting-started/install-qovery/azure/cluster-managed-by-qovery/quickstart":{"component":"17896441","content":"256f5506"},"/docs/getting-started/install-qovery/azure/self-managed-cluster":{"component":"17896441","content":"ac0a13b6"},"/docs/getting-started/install-qovery/gcp":{"component":"17896441","content":"d99b987c"},"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery":{"component":"17896441","content":"cc3d7007"},"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/create-credentials":{"component":"17896441","content":"be464708"},"/docs/getting-started/install-qovery/gcp/cluster-managed-by-qovery/quickstart":{"component":"17896441","content":"150479d1"},"/docs/getting-started/install-qovery/gcp/self-managed-cluster":{"component":"17896441","content":"b49a87dd"},"/docs/getting-started/install-qovery/kubernetes":{"component":"17896441","content":"87080b01"},"/docs/getting-started/install-qovery/kubernetes/byok-config":{"component":"17896441","content":"3ccabad0"},"/docs/getting-started/install-qovery/kubernetes/faq":{"component":"17896441","content":"6f4ba85a"},"/docs/getting-started/install-qovery/kubernetes/quickstart":{"component":"17896441","content":"9d099993"},"/docs/getting-started/install-qovery/kubernetes/validate-installation":{"component":"17896441","content":"b91b4421"},"/docs/getting-started/install-qovery/local":{"component":"17896441","content":"60154927"},"/docs/getting-started/install-qovery/scaleway":{"component":"17896441","content":"9c253a96"},"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery":{"component":"17896441","content":"b0059451"},"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/create-credentials":{"component":"17896441","content":"40c64f54"},"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/faq":{"component":"17896441","content":"b557ef1e"},"/docs/getting-started/install-qovery/scaleway/cluster-managed-by-qovery/quickstart":{"component":"17896441","content":"27d7a36c"},"/docs/getting-started/install-qovery/scaleway/self-managed-cluster":{"component":"17896441","content":"952063ba"},"/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/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/helm":{"component":"17896441","content":"02ec211a"},"/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/helm-repository":{"component":"17896441","content":"2737c3be"},"/docs/using-qovery/configuration/organization/labels-annotations":{"component":"17896441","content":"91bdc394"},"/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/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/helm-repository":{"component":"17896441","content":"8bd1b610"},"/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/cluster-troubleshoot":{"component":"17896441","content":"3cfde410"},"/docs/using-qovery/troubleshoot/service-deployment-troubleshoot":{"component":"17896441","content":"1350cb71"},"/docs/using-qovery/troubleshoot/service-run-troubleshoot":{"component":"17896441","content":"b538f6fb"}}')},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),u=l.querySelector(o.barSelector),c=o.speed,d=o.easing;return l.offsetWidth,a((function(t){""===o.positionUsing&&(o.positionUsing=n.getPositioningCSS()),s(u,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?(s(l,{transition:"none",opacity:1}),l.offsetWidth,setTimeout((function(){s(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");u(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 s(a,{transition:"all 0 linear",transform:"translate3d("+l+"%,0,0)"}),o.showSpinner||(r=t.querySelector(o.spinnerSelector))&&p(r),c!=document.body&&u(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()}}(),s=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 u(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),s=n(7),l=(n(15),n(1)),u=n(9),c=n(4),d=function(e){function t(){for(var t,n=arguments.length,o=new Array(n),r=0;r1&&s.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;q=_-y,k=e.slice(w,S),P.index-=w}else{p.lastIndex=0;var P=p.exec(k),q=1}if(P){g&&(h=P[1]?P[1].length:0),E=(x=P.index+h)+(P=P[0].slice(h)).length;var C=k.slice(0,x),O=k.slice(E),A=[y,q];C&&(++y,w+=C.length,A.push(C));var R=new l(u,f?r.tokenize(P,f):P,b,P,m);if(A.push(R),O&&A.push(O),Array.prototype.splice.apply(t,A),1!=q&&r.matchGrammar(e,t,n,y,w,!0,u),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 s=Object.keys(o.attributes).map((function(e){return e+'="'+(o.attributes[e]||"").replace(/"/g,""")+'"'})).join(" ");return"<"+o.tag+' class="'+o.classes.join(" ")+'"'+(s?" "+s:"")+">"+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--:s=!0),(s||"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,s=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,s=a.length;-1!==n.code.indexOf(r=t(o,s));)++s;return a[s]=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(s){for(var l=0;l=i.length);l++){var u=s[l];if("string"==typeof u||u.content&&"string"==typeof u.content){var c=i[r],d=n.tokenStack[c],p="string"==typeof u?u:u.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 u?s.splice.apply(s,[l,1].concat(v)):u.content=v}}else u.content&&a(u.content)}return s}(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 s(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 u(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=s(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,s=i.indexOf(r);if(-1!==s){++a;var l=i.substring(0,s),d=u(c[r]),f=i.substring(s+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 s=a.util.clone(a.languages.typescript);a.languages.tsx=a.languages.extend("jsx",s),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),s=n(2),l=n(45),u=s("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=s(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[u]=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,s=n(44),l=n(5),u=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,q="process"==c(_),C=function(){},O=r=y.f,A=!!function(){try{var e=P.resolve(1),t=(e.constructor={})[n(2)("species")]=function(e){e(C,C)};return(q||"function"==typeof PromiseRejectionEvent)&&e.then(C)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,s=r?t.ok:t.fail,l=t.resolve,u=t.reject,c=t.domain;try{s?(r||(2==e._h&&j(e),e._h=1),!0===s?n=o:(c&&c.enter(),n=s(o),c&&(c.exit(),a=!0)),n===t.promise?u(E("Promise-chain cycle")):(i=R(n))?i.call(n,l,u):l(n)):u(o)}catch(d){c&&!a&&c.exit(),u(d)}};n.length>i;)a(n[i++]);e._c=[],e._n=!1,t&&!e._h&&z(e)}))}},z=function(e){b.call(l,(function(){var t,n,o,r=e._v,i=I(e);if(i&&(t=w((function(){q?_.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=q||I(e)?2:1),e._a=void 0,i&&t.e)throw t.v}))},I=function(e){return 1!==e._h&&0===(e._a||e._c).length},j=function(e){b.call(l,(function(){var t;q?_.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,u(F,o,1),u(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)}}};A||(P=function(e){g(this,P,"Promise","_h"),f(e),o.call(this);try{e(u(F,this,1),u(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=O(h(this,P));return n.ok="function"!=typeof e||e,n.fail="function"==typeof t&&t,n.domain=q?_.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=u(F,e,1),this.reject=u(L,e,1)},y.f=O=function(e){return e===P||e===a?new i(e):r(e)}),d(d.G+d.W+d.F*!A,{Promise:P}),n(41)(P,"Promise"),n(94)("Promise"),a=n(17).Promise,d(d.S+d.F*!A,"Promise",{reject:function(e){var t=O(this);return(0,t.reject)(e),t.promise}}),d(d.S+d.F*(s||!A),"Promise",{resolve:function(e){return x(s&&this===a?P:this,e)}}),d(d.S+d.F*!(A&&n(83)((function(e){P.all(e).catch(C)}))),"Promise",{all:function(e){var t=this,n=O(t),o=n.resolve,r=n.reject,i=w((function(){var n=[],i=0,a=1;m(e,!1,(function(e){var s=i++,l=!1;n.push(void 0),a++,t.resolve(e).then((function(e){l||(l=!0,n[s]=e,--a||o(n))}),r)})),--a||o(n)}));return i.e&&r(i.v),n.promise},race:function(e){var t=this,n=O(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),s=n(24),l=n(105),u=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),q=m?E?k("entries"):P:void 0,C="Array"==t&&S.entries||T;if(C&&(w=c(C.call(new e)))!==Object.prototype&&w.next&&(u(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),s[t]=P,s[x]=f,m)if(v={values:E?P:k("values"),keys:h?P:k("keys"),entries:q},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,s=String(r(t)),l=o(n),u=s.length;return l<0||l>=u?e?"":void 0:(i=s.charCodeAt(l))<55296||i>56319||l+1===u||(a=s.charCodeAt(l+1))<56320||a>57343?e?s.charAt(l):i:e?s.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),s=n(121),l=n(66),u=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(){s("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 u("script")?function(e){l.appendChild(u("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},s={};function l(e){return o.isMemo(e)?a:s[e.$$typeof]||r}s[o.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},s[o.Memo]=a;var u=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 s=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=s(p,i(d.lastIndex),b))}for(var w,k="",x=0,E=0;E=x&&(k+=p.slice(x,S)+O,x=S+_.length)}return k+p.slice(x)}];function m(e,t,o,i,a,s){var l=o+e.length,u=i.length,c=f;return void 0!==a&&(a=r(a),c=p),n.call(s,c,(function(n,r){var s;switch(r.charAt(0)){case"$":return"$";case"&":return e;case"`":return t.slice(0,o);case"'":return t.slice(l);case"<":s=a[r.slice(1,-1)];break;default:var c=+r;if(0===c)return n;if(c>u){var p=d(c/10);return 0===p?n:p<=u?void 0===i[p-1]?r.charAt(1):i[p-1]+r.charAt(1):n}s=i[c-1]}return void 0===s?"":s}))}}))},function(e,t,n){"use strict";var o=n(95),r=n(8),i=n(63),a=n(60),s=n(26),l=n(55),u=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,s,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=u.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]?!s&&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 u=r(e),p=String(this),f=i(u,RegExp),h=u.unicode,b=(u.ignoreCase?"i":"")+(u.multiline?"m":"")+(u.unicode?"u":"")+(g?"y":"g"),v=new f(g?u:"^(?:"+u.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),s=n(26),l=n(93),u={},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=s(e.length);f>y;y++)if((h=t?v(a(g=e[y])[0],g[1]):v(e[y]))===u||h===c)return h}else for(m=b.call(e);!(g=m.next()).done;)if((h=r(m,v,g.value,t))===u||h===c)return h}).BREAK=u,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],s=i[o]();s.next=function(){return{done:n=!0}},i[o]=function(){return s},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"),s=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("