PipeCD – Example https://pipecd.dev/categories/example/ Recent content in Example on PipeCD Hugo -- gohugo.io en Thu, 14 Mar 2024 00:00:00 +0000 Blog: Control Plane on local by docker-compose https://pipecd.dev/blog/2024/03/14/control-plane-on-local-by-docker-compose/ Thu, 14 Mar 2024 00:00:00 +0000 https://pipecd.dev/blog/2024/03/14/control-plane-on-local-by-docker-compose/ <p>Currently, you can deploy and operate a PipeCD Control Plane on a Kubernetes cluster or <a href="https://pipecd.dev/blog/2023/02/07/pipecd-best-practice-02-control-plane-on-ecs/">on Amazon ECS</a>. However, some developers would like to build a Control Plane more easily for introduction or development. This blog shows you how to install a PipeCD Control Plane on local machine easily.</p> <p>This blog is for those who would like to:</p> <ul> <li>begin using PipeCD and experiment its features instantly, including Control Plane and Piped</li> </ul> <h3 id="architecture">Architecture</h3> <p>The general architecture of PipeCD Control Plane is as below. <img src="https://pipecd.dev/images/control-plane-components.png" alt=""></p> <blockquote> <p>Note: See <a href="https://pipecd.dev/docs/user-guide/managing-controlplane/architecture-overview/">Architecture Overview</a> doc for details. In this blog, you will build a Control Plane by these containers:</p></blockquote> <ul> <li>Server: pipecd server</li> <li>Ops: pipecd ops</li> <li>Cache: Redis</li> <li>Data Store: MySQL</li> <li>File Store: MinIO</li> </ul> <h3 id="installation-of-control-plane">Installation of Control Plane</h3> <ol> <li> <p>Get the demo codes from <a href="https://github.com/pipe-cd/demo/blob/main/control_plane/docker-compose/">https://github.com/pipe-cd/demo/blob/main/control_plane/docker-compose/</a></p> </li> <li> <p>Execute the below command for docker-compose.yaml you got in [1.].</p> </li> </ol> <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>docker-compose up </span></span></code></pre></div><p>After executing the above command, you will see logs like below if success.</p> <pre tabindex="0"><code class="language-log" data-lang="log">pipecd-server-1 | successfully loaded control-plane configuration pipecd-server-1 | successfully connected to file store pipecd-server-1 | successfully connected to data store pipecd-server-1 | grpc server will be run without tls pipecd-server-1 | grpc server will be run without tls pipecd-server-1 | grpc server is running on [::]:9080 pipecd-server-1 | grpc server is running on [::]:9083 pipecd-server-1 | grpc server will be run without tls pipecd-server-1 | admin server is running on 9085 pipecd-server-1 | grpc server is running on [::]:9081 pipecd-server-1 | start running http server on :9082 </code></pre><h3 id="to-confirm-access-the-console-of-the-control-plane">To confirm: Access the console of the Control Plane</h3> <ol> <li> <p>Access http://localhost:8080 on your web browser.</p> </li> <li> <p>Enter a value as below and <code>CONTINUE</code>.</p> <ul> <li><code>Project Name</code>: <code>control-plane-local</code></li> </ul> </li> <li> <p>Enter values as below and <code>LOGIN</code>.</p> <ul> <li><code>Username</code>: <code>hello-pipecd</code></li> <li><code>Password</code>: <code>hello-pipecd</code></li> </ul> </li> <li> <p>You will see the applications page. Success!</p> </li> </ol> <p><img src="https://pipecd.dev/images/control-plane-local-console.png" alt=""></p> <h3 id="clean-up">Clean up</h3> <p>To clean up the Control Plane, execute the below command.</p> <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>docker-compose down </span></span></code></pre></div><blockquote> <p>Note: By following commands instead of above one, you can keep data such as Piped or applications on the Control Plane even after restarting/updating the server component.</p></blockquote> <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#8f5902;font-style:italic"># Restart only the server component.</span> </span></span><span style="display:flex;"><span>docker-compose rm -fsv pipecd-server </span></span><span style="display:flex;"><span>docker-compose up pipecd-server </span></span></code></pre></div> Blog: PipeCD best practice 02 - control plane on ECS https://pipecd.dev/blog/2023/02/07/pipecd-best-practice-02-control-plane-on-ecs/ Tue, 07 Feb 2023 00:00:00 +0000 https://pipecd.dev/blog/2023/02/07/pipecd-best-practice-02-control-plane-on-ecs/ <p>This blog is a part of PipeCD best practice series, a guideline for you to operate your own PipeCD. Currently, you can deploy and operate the PipeCD control plane on a Kubernetes cluster easily, but some developers that would like to introduce PipeCD can not prepare Kubernetes environments. If you have the same problem, this blog is for you. We will show you how to deploy the PipeCD control plane on Amazon ECS.</p> <h3 id="architecture">Architecture</h3> <blockquote> <p>Note: Please refer to <a href="https://pipecd.dev/docs/user-guide/managing-controlplane/architecture-overview/">architecture-overview</a> docs for definitions of PipeCD components such as server, ops, cache, datastore and filestore.</p></blockquote> <p><img src="https://pipecd.dev/images/control-plane-on-ecs.png" alt=""></p> <p>Following the above graph for PipeCD control plane runs on Amazon ECS, we have to prepare these next components</p> <h3 id="secrets-manager">Secrets Manager</h3> <p>You should put config files (control-plane-config.yaml, envoy-config.yaml) on Secrets Manager because config files contain some credentials such as database passwords. The examples of config files for ECS are <a href="https://github.com/pipe-cd/control-plane-aws-ecs-terraform-demo/tree/main/config">here</a>. Please edit these files according to your environment.</p> <pre tabindex="0"><code>aws secretsmanager create-secret --name control-plane-config \ --description &#34;Configuration of control plane&#34; \ --secret-string `base64 control-plane-config.yaml` aws secretsmanager create-secret --name envoy-config \ --description &#34;Configuration of control plane&#34; \ --secret-string `base64 envoy-config.yaml` </code></pre><p>You should also put encryption key</p> <pre tabindex="0"><code>aws secretsmanager create-secret --name encryption-key \ --description &#34;Encryption key for control plane&#34; \ --secret-string `openssl rand 64 | base64` </code></pre><h3 id="rdsdatastore">RDS(datastore)</h3> <p>It is possible to use RDS as a datastore. Edit your configuration file for the control plane according to your RDS setting.</p> <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">datastore</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span></span></span><span style="display:flex;"><span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">type</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000">MYSQL</span><span style="color:#f8f8f8;text-decoration:underline"> </span></span></span><span style="display:flex;"><span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">config</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span></span></span><span style="display:flex;"><span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">url</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000">root:password@tcp(endpoint_of_rds:3306) </span><span style="color:#f8f8f8;text-decoration:underline"> </span></span></span><span style="display:flex;"><span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">database</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000">quickstart</span><span style="color:#f8f8f8;text-decoration:underline"> </span></span></span></code></pre></div><h3 id="rediscache">Redis(cache)</h3> <p>It is possible to use Redis as a cache. Note the endpoint of Redis for the task definition.</p> <h3 id="s3filestore">S3(filestore)</h3> <p>It is possible to use S3 as a filestore. The filestore contains state files that describe your secure infrastructure, so make sure to make the bucket private. Only allow pipecd-server(ECS) to access this bucket.</p> <h3 id="ecs">ECS</h3> <p>You need to create two different services for pipecd-server and a pipecd-ops because they have the same ports and different permissions. The pipecd-server can be accessed by external clients such as piped or web clients, so this service includes the pipe-cd gateway and this service must be connected to the application loadbalancer. The pipecd-ops can only be accessed by admin users, so this service must only be accessed via SSM session manager. ECS agent sets config files as environment variables in container from secrets manager. Create configuration files from environment variables in the container as below.</p> <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#204a87">echo</span> <span style="color:#000">$ENVOY_CONFIG</span><span style="color:#000;font-weight:bold">;</span> <span style="color:#204a87">echo</span> <span style="color:#000">$ENVOY_CONFIG</span> <span style="color:#000;font-weight:bold">|</span> base64 -d &gt;&gt; envoy-config.yaml </span></span></code></pre></div><blockquote> <p>Note: Attach IAM policy to get secrets from Secrets Manager to task execution role.</p></blockquote> <blockquote> <p>Note: If you manage both of RDS and ECS by terraform, you can rewite datastore endpoint in the configuration file. <code>sed -i -e s/pipecd-mysql/${var.db_instance_address}/ control-plane-config.yaml;</code></p></blockquote> <blockquote> <p>Note: Attach IAM policy to access filestore to task role.</p></blockquote> <h4 id="task-definitions-examples-using-terraform-variables">task definitions examples (using terraform variables)</h4> <ol> <li>gateway and server</li> </ol> <pre tabindex="0"><code>{ name = &#34;pipecd-gateway&#34; image = var.gateway_image_url portMappings = [ { hostPort = 9090 containerPort = 9090 protocol = &#34;tcp&#34; } ] essential = false command = [ &#34;/bin/sh -c &#39;echo $ENVOY_CONFIG; echo $ENVOY_CONFIG | base64 -d &gt;&gt; envoy-config.yaml; envoy -c envoy-config.yaml;&#39;&#34; ] entrypoint = [ &#34;sh&#34;, &#34;-c&#34; ] secrets = [ { &#34;name&#34; : &#34;ENVOY_CONFIG&#34;, &#34;valueFrom&#34; : &#34;arn:aws:secretsmanager:${data.aws_region.current.id}:${data.aws_caller_identity.self.account_id}:secret:${var.envoy_config_secret}&#34; }, ] }, { name = &#34;pipecd-server&#34; image = var.server_image_url portMappings = [ ] command = [ &#34;/bin/sh -c &#39;echo $CONTROL_PLANE_CONFIG; echo $CONTROL_PLANE_CONFIG | base64 -d &gt;&gt; control-plane-config.yaml; sed -i -e s/pipecd-mysql/${var.db_instance_address}/ control-plane-config.yaml; echo $ENCRYPTION_KEY &gt;&gt; encryption-key; pipecd server --insecure-cookie=true --cache-address=${var.redis_host}:6379 --config-file=control-plane-config.yaml --enable-grpc-reflection=false --encryption-key-file=encryption-key --log-encoding=humanize --metrics=true;&#39;&#34; ] entrypoint = [ &#34;sh&#34;, &#34;-c&#34; ] secrets = [ { &#34;name&#34; : &#34;ENCRYPTION_KEY&#34;, &#34;valueFrom&#34; : &#34;arn:aws:secretsmanager:${data.aws_region.current.id}:${data.aws_caller_identity.self.account_id}:secret:${var.encryption_key_secret}&#34; }, { &#34;name&#34; : &#34;CONTROL_PLANE_CONFIG&#34;, &#34;valueFrom&#34; : &#34;arn:aws:secretsmanager:${data.aws_region.current.id}:${data.aws_caller_identity.self.account_id}:secret:${var.control_plane_config_secret}&#34; }, ] }, </code></pre><ol start="2"> <li>ops</li> </ol> <pre tabindex="0"><code>{ name = &#34;pipecd-ops&#34; image = var.ops_image_url portMappings = [ { &#34;name&#34; : &#34;http&#34;, &#34;protocol&#34; : &#34;tcp&#34;, &#34;containerPort&#34; : 9082, &#34;appProtocol&#34; : &#34;http&#34; }, { &#34;name&#34; : &#34;http&#34;, &#34;protocol&#34; : &#34;tcp&#34;, &#34;containerPort&#34; : 9085, &#34;appProtocol&#34; : &#34;http&#34; }, ] command = [ &#34;/bin/sh -c &#39;echo $CONTROL_PLANE_CONFIG; echo $CONTROL_PLANE_CONFIG | base64 -d &gt;&gt; control-plane-config.yaml; sed -i -e s/pipecd-mysql/${var.db_instance_address}/ control-plane-config.yaml; echo $ENCRYPTION_KEY &gt;&gt; encryption-key; pipecd ops --cache-address=${var.redis_host}:6379 --config-file=control-plane-config.yaml --log-encoding=humanize --metrics=true;&#39;&#34; ] entrypoint = [ &#34;sh&#34;, &#34;-c&#34; ] secrets = [ { &#34;name&#34; : &#34;ENCRYPTION_KEY&#34;, &#34;valueFrom&#34; : &#34;arn:aws:secretsmanager:${data.aws_region.current.id}:${data.aws_caller_identity.self.account_id}:secret:${var.encryption_key_secret}&#34; }, { &#34;name&#34; : &#34;CONTROL_PLANE_CONFIG&#34;, &#34;valueFrom&#34; : &#34;arn:aws:secretsmanager:${data.aws_region.current.id}:${data.aws_caller_identity.self.account_id}:secret:${var.control_plane_config_secret}&#34; }, ] }, </code></pre><h3 id="alb">ALB</h3> <p>You must prepare two target groups for both HTTP and gRPC. Make two hosts and listner rules as below. Listner protocol should be HTTPS becuase it uses gRPC.</p> <p><img src="https://pipecd.dev/images/control-plane-alb.png" alt=""></p> <h3 id="terraform-example">Terraform example</h3> <p>PipeCD gives <a href="https://github.com/pipe-cd/control-plane-aws-ecs-terraform-demo">control-plane-aws-ecs-terraform-demo</a>, which we use Terraform to prepare PipeCD controlplane components and install it on air.</p> <h4 id="prepare">Prepare</h4> <ol> <li> <p>Prepare SSL certificate Prepare your domain and SSL certificate from AWS certificate manager.</p> </li> <li> <p>Create a s3 bucket for terraform backend Write bucket name to <code>00-main.tf</code></p> </li> </ol> <pre tabindex="0"><code>terraform { backend &#34;s3&#34; { bucket = &#34;example-pipecd-control-plane-tfstate&#34; #your bucket name for terraform backend region = &#34;ap-northeast-1&#34; key = &#34;tfstate&#34; profile = &#34;pipecd-control-planeg-terraform&#34; #your profile } required_providers { aws = { version = &#34;~&gt; 3.34.0&#34; } } } </code></pre><ol start="3"> <li>Edit <code>variables.tf</code> for your project</li> </ol> <pre tabindex="0"><code>//export locals { alb = { certificate_arn = &#34;&#34; } redis = { node_type = &#34;cache.t2.micro&#34; } rds = { node_type = &#34;db.t3.micro&#34; } ecs = { memory = &#34;1024&#34; cpu = &#34;512&#34; } } </code></pre><ol start="4"> <li>Create a S3 bucket for filestore and write the bucket name for it to <code>control-plane-config.yaml</code> and <code>variables.tf</code></li> </ol> <pre tabindex="0"><code>apiVersion: &#34;pipecd.dev/v1beta1&#34; kind: ControlPlane spec: datastore: type: MYSQL config: url: sample:test@tcp(pipecd-mysql:3306) database: quickstart filestore: type: S3 config: # edit here bucket: example-pipecd-control-plane-filestore region: ap-northeast-1 projects: - id: quickstart staticAdmin: username: hello-pipecd passwordHash: &#34;$2a$10$ye96mUqUqTnjUqgwQJbJzel/LJibRhUnmzyypACkvrTSnQpVFZ7qK&#34; # bcrypt value of &#34;hello-pipecd&#34; </code></pre><pre tabindex="0"><code>//export locals { s3 = { # These must be unique in the world. filestore_bucket = &#34;${local.project}-filestore&#34; # edit here } } </code></pre><ol start="5"> <li>Write config of RDS for datastore to <code>control-plane-config.yaml</code> Note: Do not edit hostname (pipecd-mysql) because it will be edited autimaticaly by terraform.</li> </ol> <pre tabindex="0"><code>apiVersion: &#34;pipecd.dev/v1beta1&#34; kind: ControlPlane spec: datastore: type: MYSQL config: # edit here url: sample:test@tcp(pipecd-mysql:3306) database: quickstart filestore: type: S3 config: bucket: example-pipecd-control-plane-filestore region: ap-northeast-1 projects: - id: quickstart staticAdmin: username: hello-pipecd passwordHash: &#34;$2a$10$ye96mUqUqTnjUqgwQJbJzel/LJibRhUnmzyypACkvrTSnQpVFZ7qK&#34; # bcrypt value of &#34;hello-pipecd&#34; </code></pre><ol start="6"> <li>Put an encryption key and config file in Secrets Manager and write the path to <code>variables.tf</code></li> </ol> <pre tabindex="0"><code>locals { sm = { control_plane_config_secret = &#34;&#34; envoy_config_secret = &#34;&#34; encryption_key_secret = &#34;&#34; } } </code></pre><h4 id="deploy">Deploy</h4> <pre tabindex="0"><code>terraform apply </code></pre><h4 id="login-admin-console">login admin console</h4> <p>You can login pipecd-ops via ECS exec.</p> <pre tabindex="0"><code>aws ssm start-session --target ecs:${CLUSTER}_${TASK_ID}_${CONTAINER_ID} --document-name AWS-StartPortForwardingSession --parameters &#39;{&#34;portNumber&#34;:[&#34;9082&#34;],&#34;localPortNumber&#34;:[&#34;19082&#34;]}&#39; </code></pre><p>That&rsquo;s all! Now you have your own PipeCD controlplane and it&rsquo;s ready to go!!</p>