-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 64fb604
Showing
14 changed files
with
449 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
.terraform | ||
*tfvars* | ||
*tfplan* | ||
*tfstate* | ||
.key |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# GCP & GKE Terraform CI/CD Setup | ||
|
||
This is demonstration how to make basic CI/CD pipeline setup using Jenkins and SonarQube in GCP. | ||
|
||
### Terraform Setup | ||
- Make sure terraform exist in OS path. To test, type `which terraform`. | ||
- In terminal, create new file `terraform.tfvars`. | ||
|
||
``` | ||
project = "project_id" # set your GCP progect id | ||
region = "us-central1" | ||
zone = "us-central1-c" | ||
size = "n1-standard-2" | ||
public_key = ".key/user.pub" | ||
private_key = ".key/user.pem" | ||
master_user = "user" | ||
master_pass = "abcdefghij123" # password must be at least 16 characters | ||
app_repo = "https://github.com/incubus8/gcp-cicd-terraform-jenkins.git" | ||
``` | ||
|
||
### Create SSH .key | ||
- create ssh key `ssh-keygen -f user.pem -N""` # leave an empty password | ||
- rename public to `.pub` | ||
- place both in `.key` subdir | ||
|
||
### IAM Setup | ||
- enable Kubernetes Engine API by visiting service console | ||
- Console -> IAM & admin -> Service accounts -> select default account (or create new) -> Edit -> Create Key -> Json | ||
- place the service account key file into the `.key/account.json` | ||
|
||
### GCP Build Server Setup | ||
|
||
- In terminal, type `terraform init`, then `terraform apply` | ||
- Login to build server http://{terraform.output.build}:8080/ | ||
- Create SERVICE_ACCOUNT_KEY secret file (Jenkins -> Credentials -> Global Credentials -> Add Credentials) | ||
* SERVICE_ACCOUNT_KEY { type = secret file } For secrets file, use '.key/account.json' | ||
- Create new project using `pipeline` template and paste `jenkins/Jenkinsfile` content | ||
- Manage Jenkins -> Manage Plugins -> Available -> filter: sonar -> SonarQube Scanner for Jenkins -> Install and restart | ||
- Manage Jenkins -> Configure System -> SonarQube servers -> Add SonarQube -> Name: sonar, Host: http://{terraform.output.sonar}:9000 -> Save | ||
- Manage Jenkins -> Global Tool Configuration -> Add SonarQube Scanner -> Name: scanner -> Save | ||
- Enable Poll SCM, if CI mode is required | ||
|
||
### Test | ||
- App url `http://{terraform.output.app}:5000` | ||
- Jenkins URL server `http://{terraform.output.build}:8080` | ||
- SonarQube `http://{terraform.output.sonar}:9000` | ||
|
||
### Destroy | ||
|
||
In terminal, type: | ||
|
||
``` | ||
terraform destroy | ||
``` | ||
|
||
## Attention | ||
|
||
This is just a demo pipeline. You may want to setup more strict security if you want to apply in production. | ||
|
||
## Further Improvement | ||
- Deploy using Kubernetes Control Plane | ||
|
||
Jakarta (c) 2019 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# Defining pod & policy for a node.js hellow-world app | ||
|
||
locals { | ||
port = "5000" | ||
app = "app" | ||
} | ||
|
||
resource "kubernetes_deployment" "app" { | ||
metadata { | ||
name = "${local.app}" | ||
|
||
labels { | ||
app = "${local.app}" | ||
} | ||
} | ||
|
||
spec { | ||
replicas = 3 | ||
|
||
selector { | ||
match_labels { | ||
app = "${local.app}" | ||
} | ||
} | ||
|
||
template { | ||
metadata { | ||
labels { | ||
app = "${local.app}" | ||
} | ||
} | ||
|
||
spec { | ||
container { | ||
image = "malferov/app:3" # temporary "gcr.io/google-samples/node-hello:1.0" | ||
name = "${local.app}" | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
resource "kubernetes_service" "app" { | ||
metadata { | ||
name = "${local.app}" | ||
} | ||
|
||
spec { | ||
selector { | ||
app = "${kubernetes_deployment.app.metadata.0.labels.app}" | ||
} | ||
|
||
session_affinity = "ClientIP" | ||
|
||
port { | ||
port = "${local.port}" | ||
} | ||
|
||
type = "LoadBalancer" | ||
} | ||
} | ||
|
||
output "app" { | ||
value = "${kubernetes_service.app.load_balancer_ingress.0.ip}:${local.port}" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
FROM node:8 | ||
|
||
ARG port | ||
|
||
EXPOSE $port | ||
|
||
COPY app.js . | ||
|
||
ENTRYPOINT ["node", "app.js"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
const http = require('http'); | ||
const os = require("os"); | ||
const bind = '0.0.0.0'; | ||
const port = process.argv[2] || 5000; | ||
|
||
const version = '1.6'; | ||
|
||
const server = http.createServer((req, res) => { | ||
res.statusCode = 200; | ||
res.setHeader('Content-Type', 'text/plain'); | ||
res.end( | ||
JSON.stringify({ | ||
data: 'welcome', | ||
version: version, | ||
build: process.argv[3], | ||
lang: 'js', | ||
hostname: os.hostname(), | ||
}) | ||
); | ||
}); | ||
|
||
server.listen(port, bind, () => { | ||
console.log(`Server running at http://${bind}:${port}/`) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# Build server - Jenkins Docker container on GCP VM | ||
|
||
variable "app_repo" {} | ||
variable "size" {} | ||
variable "public_key" {} | ||
variable "private_key" {} | ||
|
||
locals { | ||
yum = "sudo yum -y -d 1 install" | ||
image = "centos-7" | ||
user = "centos" | ||
} | ||
|
||
resource "google_compute_instance" "build" { | ||
name = "build" | ||
machine_type = "${var.size}" | ||
|
||
boot_disk { | ||
initialize_params { | ||
image = "${local.image}" | ||
} | ||
} | ||
|
||
network_interface { | ||
network = "${data.google_compute_network.net.name}" | ||
access_config = {} | ||
} | ||
|
||
metadata { | ||
sshKeys = "${local.user}:${file(var.public_key)}" | ||
} | ||
|
||
connection { | ||
user = "${local.user}" | ||
private_key = "${file(var.private_key)}" | ||
} | ||
|
||
provisioner "file" { | ||
source = "jenkins" | ||
destination = "~" | ||
} | ||
|
||
provisioner "file" { | ||
content = "${local.kubeconfig}" | ||
destination = "config" | ||
} | ||
|
||
provisioner "remote-exec" { | ||
inline = [ | ||
"${local.yum} docker git mc", | ||
"sudo systemctl start docker", | ||
"sudo git clone ${var.app_repo} && cd cicd-tools-gcp-terraform/jenkins", | ||
"sudo docker build -t jenkins . && cd ~", | ||
"sudo chmod 777 /var/run/docker.sock", | ||
"sudo docker run -d -p 8080:8080 -v /var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock --privileged jenkins", | ||
"sudo docker exec jenkins kubectl config set-cluster kube", | ||
"sudo docker cp config jenkins:/var/jenkins_home/.kube", | ||
] | ||
} | ||
|
||
} | ||
|
||
output "build" { | ||
value = "${google_compute_instance.build.network_interface.0.access_config.0.assigned_nat_ip}:8080" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
FROM jenkins/jenkins:lts | ||
|
||
ENV JAVA_OPTS -Djenkins.install.runSetupWizard=false | ||
|
||
# Note: Latest version of kubectl may be found at: | ||
# https://aur.archlinux.org/packages/kubectl-bin/ | ||
ENV KUBE_LATEST_VERSION="v1.11.9" | ||
|
||
# Note: Latest version of helm may be found at: | ||
# https://github.com/kubernetes/helm/releases | ||
ENV HELM_VERSION="v2.13.1" | ||
|
||
RUN install-plugins.sh github-branch-source workflow-aggregator | ||
|
||
USER root | ||
|
||
RUN apt-get update && apt-get install -y apt-transport-https | ||
|
||
ADD https://storage.googleapis.com/kubernetes-release/release/${KUBE_LATEST_VERSION}/bin/linux/amd64/kubectl /usr/local/bin/kubectl | ||
|
||
RUN chmod +x /usr/local/bin/kubectl | ||
RUN curl -sSL https://get.docker.com/ | sh | ||
RUN usermod -aG docker jenkins | ||
|
||
RUN wget -q https://storage.googleapis.com/kubernetes-helm/helm-${HELM_VERSION}-linux-amd64.tar.gz -O - | tar -xzO linux-amd64/helm > /usr/local/bin/helm \ | ||
RUN chmod +x /usr/local/bin/helm | ||
|
||
USER jenkins |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
pipeline { | ||
agent any | ||
environment { | ||
app_repo = "https://github.com/incubus8/gcp-cicd-terraform-jenkins.git" | ||
project_id = "PROJECT_ID" | ||
} | ||
stages { | ||
stage('Build') { | ||
steps { | ||
git branch: 'master', url: "${env.app_repo}" | ||
sh "echo 'CMD [\"5000\", \"$BUILD_NUMBER\"]' >> app/Dockerfile" | ||
sh "docker build -t app --build-arg port=5000 app/." | ||
sh "docker tag app gcr.io/${env.project_id}/app:$BUILD_NUMBER" | ||
withCredentials([file(credentialsId: 'SERVICE_ACCOUNT_KEY', variable: 'FILE')]) { | ||
sh "docker login -u _json_key --password-stdin https://gcr.io < $FILE" | ||
} | ||
sh "docker push gcr.io/${env.project_id}/app:$BUILD_NUMBER" | ||
} | ||
} | ||
stage('SonarQube') { | ||
steps { | ||
script { | ||
scannerHome = tool 'scanner' | ||
} | ||
withSonarQubeEnv('sonar') { | ||
sh "${scannerHome}/bin/sonar-scanner" | ||
} | ||
} | ||
} | ||
stage('Deploy') { | ||
steps { | ||
sh "kubectl set image deployment/app app=gcr.io/${env.project_id}/app:$BUILD_NUMBER" | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# Creates a GKE cluster with KUBECONFIG | ||
|
||
variable "master_user" {} | ||
variable "master_pass" {} | ||
|
||
locals { | ||
kubeconfig = <<KUBECONFIG | ||
apiVersion: v1 | ||
clusters: | ||
- cluster: | ||
insecure-skip-tls-verify: true | ||
server: https://${google_container_cluster.kube.endpoint} | ||
name: kube | ||
contexts: | ||
- context: | ||
cluster: kube | ||
user: admin | ||
name: kube | ||
current-context: kube | ||
kind: Config | ||
preferences: {} | ||
users: | ||
- name: admin | ||
user: | ||
username: ${var.master_user} | ||
password: ${var.master_pass} | ||
KUBECONFIG | ||
} | ||
|
||
resource "google_container_cluster" "kube" { | ||
name = "kube" | ||
zone = "us-central1-a" | ||
initial_node_count = 2 | ||
|
||
additional_zones = [ | ||
"us-central1-b", | ||
] | ||
|
||
master_auth { | ||
username = "${var.master_user}" | ||
password = "${var.master_pass}" | ||
} | ||
|
||
node_config { | ||
oauth_scopes = [ | ||
"https://www.googleapis.com/auth/compute", | ||
"https://www.googleapis.com/auth/devstorage.read_only", | ||
"https://www.googleapis.com/auth/logging.write", | ||
"https://www.googleapis.com/auth/monitoring", | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Defining ingress firewall rules | ||
|
||
data "google_compute_network" "net" { | ||
name = "default" | ||
} | ||
|
||
resource "google_compute_firewall" "fw" { | ||
name = "fw" | ||
network = "${data.google_compute_network.net.name}" | ||
|
||
allow { | ||
protocol = "tcp" | ||
ports = ["8080"] | ||
} | ||
|
||
source_ranges = ["0.0.0.0/0"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Defining google/kubernetest providers | ||
|
||
variable "project" {} | ||
variable "region" {} | ||
variable "zone" {} | ||
|
||
provider "google" { | ||
credentials = "${file(".key/account.json")}" | ||
project = "${var.project}" | ||
region = "${var.region}" | ||
zone = "${var.zone}" | ||
} | ||
|
||
provider "kubernetes" { | ||
host = "https://${google_container_cluster.kube.endpoint}" | ||
insecure = true | ||
load_config_file = false | ||
|
||
username = "${google_container_cluster.kube.master_auth.0.username}" | ||
password = "${google_container_cluster.kube.master_auth.0.password}" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
terraform-secret |
Oops, something went wrong.