In whichever environment we need discourse (example Staging or Production), we have to bootstrap discourse on one of the cluster’s nodes (AWS cluster created with KOPS), after having upgraded docker on the nodes to satisfy requirement for bootstrapping discourse image.
We bootstrap on one of the cluster’s nodes so that we’re in the VPC with access to pre-existing RDS Database (Postgres) and Elasticache (Redis).
I start with copying samples/web_only.yml to containers/discourse.yml
And I have to add SSL + Letsencrypt because if I disable force_https and make ELB http only origin policy, Google oauth in discourse will load over http, and discourse will mix loading assets over http/https which causes problems (ex: preview post stops working with errors in browser console about assets loaded over insecure http while connection is over https), having configured Cloudfront to redirect HTTP to HTTPS as the viewer policy.
templates:
- "templates/web.template.yml"
- "templates/web.ratelimited.template.yml"
## Uncomment these two lines if you wish to add Lets Encrypt (https)
- "templates/web.ssl.template.yml"
- "templates/web.letsencrypt.ssl.template.yml"
Then define all vars needed in the “env” section, such as:
DISCOURSE_SMTP_*
DISCOURSE_DB_* (only leave _SOCKET blank since we’re using remote RDS DB)
DISCOURSE_REDIS_HOST
Also if your RDS database is newer version, say 9.6.x, discourse backups will not work because of older pg_dump version in the image, so I also edit the template to include (at the end):
run:
- exec: apt-get -y purge postgresql-client-9.5 postgresql-9.5 postgresql-contrib-9.5
- exec: apt-get -y install postgresql-client-9.6
Then the procedure to bootstrap with the above template (discourse.yml) and push to docker hub is easy:
# rm -rf /var/discourse
# git clone https://github.com/discourse/discourse_docker.git /var/discourse
# cd /var/discourse
# cp /home/admin/discourse/discourse.yml containers/
# ./launcher destroy discourse
# ./launcher bootstrap discourse
# docker tag $(docker images local_discourse/discourse -q) myorg/discourse:PROD-20171228
# docker login
# docker push myorg/discourse:PROD-20171228
If using EBS for the /shared volume, you’ll need to first make PV & PVC for a ebs volume:
kubectl apply -f discourse_ebs.yml
apiVersion: v1
items:
- apiVersion: v1
kind: PersistentVolume
metadata:
name: ebs-discourse
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
storageClassName: ebs-discourse
awsElasticBlockStore:
volumeID: vol-xxxxxxxxxxxxxxx
fsType: ext4
- apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ebs-discourse
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
storageClassName: ebs-discourse
kind: List
metadata: {}
Finally we can deploy, using a yaml similar to the following:
apiVersion: v1
items:
- apiVersion: v1
kind: Service
metadata:
name: discourse
spec:
ports:
- name: discourse-http
port: 80
targetPort: 80
- name: discourse-https
port: 443
targetPort: 443
selector:
app: discourse
type: LoadBalancer
selector:
app: discourse
type: LoadBalancer
- apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: discourse
labels:
app: discourse
spec:
replicas: 1
strategy:
type: Recreate
template:
metadata:
labels:
app: discourse
spec:
containers:
- image: myorg/discourse:PROD-20171228
name: discourse
command: ["/sbin/boot"]
imagePullPolicy: Always
ports:
- containerPort: 80
resources:
requests:
memory: "1Gi"
env:
- name: DISCOURSE_HOSTNAME
value: forum.myorg.ngo
- name: DISCOURSE_SITE_NAME
value: 'MyOrg Forum'
- name: DISCOURSE_DEVELOPER_EMAILS
value: 'bla@myorg.ngo,bla2@myorg.ngo'
- name: DISCOURSE_DB_HOST
value: production.xxxxxxxxx.eu-central-1.rds.amazonaws.com
- name: DISCOURSE_DB_SOCKET
value: ''
- name: DISCOURSE_DB_NAME
value: 'discourse'
- name: DISCOURSE_DB_USERNAME
value: discoursedbuser
- name: DISCOURSE_DB_PASSWORD
value: LongSecurePasswordHere
- name: DISCOURSE_REDIS_HOST
value: redis-production.xxxxxx.xx.0001.euc1.cache.amazonaws.com
- name: DISCOURSE_REDIS_PORT
value: '6379'
- name: DISCOURSE_SMTP_ADDRESS
value: 'email-smtp.eu-west-1.amazonaws.com'
- name: DISCOURSE_SMTP_PORT
value: '587'
- name: DISCOURSE_SMTP_USER_NAME
value: xxxxxxxxxxxxxx
- name: DISCOURSE_SMTP_PASSWORD
value: xxxxxxxxxxxxxx
volumeMounts:
- mountPath: /shared
name: discourse-discourse-data
restartPolicy: Always
volumes:
- name: discourse-discourse-data
persistentVolumeClaim:
claimName: ebs-discourse
imagePullSecrets:
- name: services-secret
kind: List
metadata: {}
Finally go into the pod (kubectl exec -ti discourse-xxxx bash
), run rails c
, and at the prompt run SiteSetting.force_https = true
and finally exit
Now you have HTTPS-ready ELB , so you can create a CloudFront distribution with origin as that ELB using HTTPS as the origin policy, and “Redirect HTTP to HTTPS” for the viewer policy.
Important notes:
You cannot build in one environment (ex: staging) and deploy in another (ex: production). Letsencrypt template builds into the image the discourse_hostname & letsencrypt_email used at build time (which you defined in containers/discourse.yml)
Cheers