The left-handed Karunaratne, who registered his eighth century in his 50th Test, built crucial partnerships including a 63-run 10th wicket stand with Lakshan Sandakan, who made 25.
In response South Africa were in trouble at four for one at stumps after veteran spinner Rangana Herath got Aiden Markram out for nought.
The day belonged to Karunaratne who stood tall during his marathon stand after Rabada and then left-arm wrist spinner Tabraiz Shamsi tore into the Sri Lankan middle-order.
Rabada, who came back after an injury, returned figures of 4-50, while Shamsi took three wickets on a seemingly turning sub-continent pitch.
Rabada had made the first breakthrough for South Africa, dismissing Danushka Gunathilaka with a delivery that rose sharply and got the batsman caught behind for 26.
He then struck twice in his sixth over of the day, removing Angelo Mathews, for one, and Roshen Silva, for nought, shortly after lunch.
Those two wickets came towards the start of Sri Lanka's middle-order, when they lost six wickets for 61 runs, slipping from a relatively comfortable 115-2.
But Karunaratne rarely attempted to counter attack, preferring instead to steadily build his innings, which featured 13 fours and an impressive six off Dale Steyn in the first session.
He completed his ton with a boundary off Shamsi and then moved to 150 for the fourth time in his Test career.
(This story has not been edited by Business Standard staff and is auto-generated from a syndicated feed.)